一.基础知识:
1)集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet)
List:元素是有顺序的,元素可以重复因为每个元素有自己的角标(索引)
|-- ArrayList:底层是数组结构,特点是:查询很快,增删稍微慢点,线程不同步:A线程将元素放在索引0位置,CPU调度线程A停止,B运行,也将元素放在索引0位置,当A和B同时运行的时候Size就编程了2.
|-- LinkedList:底层使用的是链表数据结构,特点是:增删很快,查询慢。线程不安全,线程安全问题是由多个线程同时写或同时读写同一个资源造成的。
|--Vector:底层是数组数据结构,线程同步,Vector的方法前面加了synchronized关键字,被ArrayList代替了,现在用的只有他的枚举。
Set:元素是无序的,且不可以重复(存入和取出的顺序不一定一致),线程不同步。set底层是使用Map实现的,故可以通过ConcurrentHashMap的方式变通实现线程安全的Set。
|--HashSet:底层是哈希表数据结构。根据hashCode和equals方法来确定元素的唯一性。
hashCode和equals:作用一样,都是用来比较两个对象是否相等一致。
equals比较的比较全面,而利用hashCode()进行对比,则只要生成一个hash值进行比较久可以了,效率高。
equal()相等的两个对象他们的hashCode()肯定相等,也就是equal()是绝对可靠的。
hashCode()相等的两个对象他们的equal()不一定相等,hashCode()不是绝对可靠的。
Map:这个集合是存储键值对的,一对一对往里存,而且要确保键的唯一性(01,张三)这样的形式打印出来就是 01=张三
|--HashTable:底层是哈希表数据结构,不可以存入null键和null值,该集合线程是同步的,效率比较低。出现于JDK1.0。线程安全,使用synchronized锁住整张Hash表实现线程安全,即每次锁住整张表让线程独占。
|--HashMap:底层是哈希表数据结构,可以存入null键和null值,线程不同步,效率较高,代替了HashTable,出现于JDK 1.2
|--TreeMap:底层是二叉树数据结构,线程不同步,可以用于对map集合中的键进行排序
ConcurrentHashMap:线程安全,允许多个修改操作并发进行,其关键在于使用了锁分离技术,它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
当两个对象需要对比的时候,首先用hashCode()去对比,如果不一样,则表示这两个对象肯定不相等(也就不用再比较equal(0)了),如果hashCode()相同,再比较equal(),如果equal()相同,那两个对象就是相同的。
|--TreeSet:可以对Set集合中的元素进行排序(自然循序),底层的数据结构是二叉树,
2)HashMap的底层实现,之后会问ConcurrentHashMap的底层实现
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。允许使用null值和null键。
HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。
HashMap是基于hash算法实现的,通过put(key,value)存储对象到HashMap中,也可以通过get(key)从HashMap中获取对象。
当我们使用put的时候,首先HashMap会对key的hashCode()的值进行hash计算,根据hash值得到这个元素在数组中的位置,将元素存储在该位置的链表上。
当我们使用get的时候,首先HashMap会对key的hashCode()的值进行hash计算,根据hash值得到这个元素在数组中的位置,将元素从该位置上的链表中取出
当多线程的情况下,可能产生条件竞争。当重新调整HashMap大小的时候,确实存在条件竞争,如果两个线程都发现HashMap需要重新调整大小了,
它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的数组位置的时候,
HashMap并不会将元素放在LinkedList的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了
ConcurrentHashMap基于双数组和链表的Map接口的同步实现
ConcurrentHashMap中元素的key是唯一的、value值可重复
ConcurrentHashMap不允许使用null值和null键
ConcurrentHashMap是无序的
为什么使用ConcurrentHashMap:
我们都知道HashMap是非线程安全的,当我们只有一个线程在使用HashMap的时候,自然不会有问题,但如果涉及到多个线程,并且有读有写的过程中,HashMap就会fail-fast。要解决HashMap同步的问题,我们的解决方案有:Hashtable 、Collections.synchronizedMap(hashMap)
这两种方式基本都是对整个hash表结构加上同步锁,这样在锁表的期间,别的线程就需要等待了,无疑性能不高,所以我们引入ConcurrentHashMap,既能同步又能多线程访问
ConcurrentHashMap的数据结构:
ConcurrentHashMap的数据结构为一个Segment数组,Segment的数据结构为HashEntry的数组,而HashEntry存的是我们的键值对,可以构成链表。可以简单的理解为数组里装的是HashMap
3)如何实现HashMap顺序存储:可以参考LinkedHashMap的底层实现
LinkedHashMap底层使用哈希表与双向链表来保存所有元素,它维护着一个运行于所有条目的双向链表(如果学过双向链表的同学会更好的理解它的源代码),此链表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序
1.按插入顺序的链表:在LinkedHashMap调用get方法后,输出的顺序和输入时的相同,这就是按插入顺序的链表,默认是按插入顺序排序
2.按访问顺序的链表:在LinkedHashMap调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。简单的说,按最近最少访问的元素进行排序(类似LRU算法)
4)String,StringBuffer和StringBuilder的区别
运行速度快慢为:StringBuilder > StringBuffer > String
String最慢的原因:
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
String:适用于少量的字符串操作的情况,
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况(线程不安全)
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况(线程安全)
5)Object的方法有哪些:比如有wait方法,为什么会有
wait、notify、notifuAll
1.使用wait()、notify()和notifyAll()时需要首先对调用对象加锁
2.调用wait()方法后,线程状态会从RUNNING变为WAITING,并将当线程加入到lock对象的等待队列中
3.调用notify()或者notifyAll()方法后,等待在lock对象的等待队列的线程不会马上从wait()方法返回,必须要等到调用notify()或者notifyAll()方法的线程将lock锁释放,等待线程才有机会从等待队列返回。这里只是有机会,因为锁释放后,等待线程会出现竞争,只有竞争到该锁的线程才会从wait()方法返回,其他的线程只能继续等待
4.notify()方法将等待队列中的一个线程移到lock对象的同步队列,notifyAll()方法则是将等待队列中所有线程移到lock对象的同步队列,被移动的线程的状态由WAITING变为BLOCKED
5.wait()方法上等待锁,可以通过wait(long timeout)设置等待的超时时间
6)wait和sleep的区别,必须理解
sleep方法属于线程,wait方法属于对象
sleep休眠当前线程,不会释放对象锁,wait使当前线程进入等待状态,释放对象锁,只有针对此对象调用notify()方法(且共享对象资源释放)后本线程才会继续执行
参考: https://www.cnblogs.com/hongten/p/hongten_java_sleep_wait.html
7)JVM的内存结构,JVM的算法
JVM内存结构主要有三大块:堆内存、方法区和栈,几乎所有的对象实例都存放在堆里,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。
每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
8)强引用,软引用和弱引用的区别
强引用:
以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。
当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
软引用:
如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存
弱引用:
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。
在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存
总结:
强引用:String str = “abc”; list.add(str);
软引用:如果弱引用对象回收完之后,内存还是报警,继续回收软引用对象
弱引用:如果虚引用对象回收完之后,内存还是报警,继续回收弱引用对象
虚引用:虚拟机的内存不够使用,开始报警,这时候垃圾回收机制开始执行System.gc(); String s = “abc”;如果没有对象回收了, 就回收没虚引用的对象
9)数组在内存中如何分配
当一个对象使用关键字“new”创建时,会在堆上分配内存空间,然后返回对象的引用,这对数组来说也是一样的,因为数组也是一个对象
简单的值类型的数组,每个数组成员是一个引用(指针),引用到栈上的空间
10)用过哪些设计模式,手写一个(除单例)
1.懒汉模式
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){}
public static SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
2.饿汉模式
public class SingletonDemo {
private static SingletonDemo instance=new SingletonDemo();
private SingletonDemo(){}
public static SingletonDemo getInstance(){
return instance;
}
}
3.简单工厂模式
面条工厂:
public abstract class INoodles {
/**
* 描述每种面条啥样的
*/
public abstract void desc();
}
先来一份兰州拉面(具体的产品类):
public class LzNoodles extends INoodles {
@Override
public void desc() {
System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");
}
}
程序员加班必备也要吃泡面(具体的产品类):
public class PaoNoodles extends INoodles {
@Override
public void desc() {
System.out.println("泡面好吃 可不要贪杯");
}
}
准备工作做完了,我们来到一家“简单面馆”(简单工厂类),菜单如下:
public class SimpleNoodlesFactory {
public static final int TYPE_LZ = 1;//兰州拉面
public static final int TYPE_PM = 2;//泡面
public static INoodles createNoodles(int type) {
switch (type) {
case TYPE_LZ:
return new LzNoodles();
case TYPE_PM:
return new PaoNoodles();
default:
return new PaoNoodles();
}
}
/**
* 简单工厂模式
*/
void creat(){
INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_PM);
noodles.desc();
}
}
11)springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的
aop和ioc
流程:用户发送请求给服务器。url:user.do--->Dispatchservlet处理-->DispatchServlet通过HandleMapping调用这个url对应的Controller
Controller执行完毕后,如果返回字符串,则ViewResolver将字符串转化成相应的视图对象;如果返回ModelAndView对象,该对象本身就包含了视图对象信息。
DispatchServlet将执视图对象中的数据,输出给服务器并呈现给客户
IOC控制反转:典型的工厂模式,就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。。在Spring中BeanFactory是IOC容器的实际代表者
AOP依赖注入:典型的代理模式,面向切面编程将程序中的交叉业务逻辑(比如安全,日志,事务),封装成一个切面,然后注入到目标业务逻辑中去。
aop框架具有的两个特征: 1.各个步骤之间的良好隔离性 2.源代码无关性
12)mybatis如何处理结果集:反射,建议看看源码
通过在mapper配置文件里配置的属性对照反射进对象里
13)java的多态表现在哪里
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作
比如同一个打印机,可以打印黑白的纸张也可以打印彩色的,同样是人,却有黑人白人之分
14)接口有什么用
接口是一种规范,在这里举两个例子
1.接口就比如KFC,你一听KFC就知道是卖炸鸡薯条的,他可以有不同的分店,也可以有自己的创新食品(多态),但是招牌炸鸡、鸡肉卷、全家桶什么的肯定会有,
你不用进店看菜单就知道他有,但如果不叫KFC换成炸鸡店你也可以吃到炸鸡,但是你不进店看菜单你不知道他具体都卖的有哪些食品,这就是接口的好处
2.比如电插孔,多是两孔和三孔的那种,如果没有这种规范那每家电器公司都来做一种插孔的话,试想一下插头换了怎么办?是不是只能买原装的来替换了
15)说说http,https协议
http是一种超文本协议,默认端口80,以明文传输。
https是http协议的安全版,安全基础是SSL,以密文传输
16)osi五层网络协议
应用层、传输层、网络层、数据链路层、物理层
17)用过哪些加密算法
对称加密,非对称加密算法,Base64加密算法,MD5加密算法,SHA1加密算法
18)说说tcp三次握手,四次挥手
1.客户端向服务器发送一个syn包,进入发送状态
2.服务器收到syn包,确认客户的syn,并向客户端发送syn+ack包,进入接受状态
3.客户端接受的来自服务的的syn包信息,向服务的发出ack包,次数两者进入tcp连接成功状态
19)cookie和session的区别,分布式环境怎么保存用户状态
cookie存在客户端,session存在服务端
分布式Session的几种实现方式
1.基于数据库的Session共享
2.基于NFS共享文件系统
3.基于memcached 的session,如何保证 memcached 本身的高可用性?
4.基于resin/tomcat web容器本身的session复制机制
5.基于TT/Redis 或 jbosscache 进行 session 共享。
6.基于cookie 进行session共享(唯一值token)
20)git,svn区别
Git是分布式的,而Svn不是分布的
Git下载下来后,在OffLine状态下可以看到所有的Log,SVN不可以
SVN的特点是简单,只是需要一个放代码的地方时用是OK的,Git的特点版本控制可以不依赖网络做任何事情,对分支和合并有更好的支持
21)请写一段栈溢出、堆溢出的代码
堆溢出,死循环存值,JVM就会抛出OutOfMemoryError:java heap space异常
public static void main(String[] args) {
List list = new ArrayList<>();
int i=0;
while(true){
list.add(new byte[5*1024*1024]);
System.out.println("分配次数:"+(++i));
}
}
栈溢出,栈空间不足——StackOverflowError实例
public class StackSOFTest {
int depth = 0;
public void sofMethod(){
depth ++ ;
sofMethod();
}
public static void main(String[] args) {
StackSOFTest test = null;
try {
test = new StackSOFTest();
test.sofMethod();
} finally {
System.out.println("递归次数:"+test.depth);
}
}
}
22)ThreadLocal可以用来共享数据吗
可以
ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
二.IO:
1)bio,nio,aio的区别;
2)nio框架:dubbo的实现原理;
3)京东内部的jsf是使用的什么协议通讯:可参见dubbo的协议;
三.算法:
1)java中常说的堆和栈,分别是什么数据结构;另外,为什么要分为堆和栈来存储数据。
2)TreeMap如何插入数据:二叉树的左旋,右旋,双旋
3)一个排序之后的数组,插入数据,可以使用什么方法?答:二分法;问:时间复杂度是多少?
4)平衡二叉树的时间复杂度
5)Hash算法和二叉树算法分别什么时候用
6)图的广度优先算法和深度优先算法:详见jvm中垃圾回收实现
三.多线程相关
1)说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行)
2)进程通讯的方式:消息队列,共享内存,信号量,socket通讯等
3)用过并发包的哪些类
4)什么地方用了多线程
5)Excutors可以产生哪些线程池
6)为什么要用线程池
有效管理线程资源
7)volatile关键字的用法
使多线程中的变量可见,但是没有原子性
四.数据库相关(mysql)
1)msyql优化经验
EXPLAIN 你的 SELECT 查询
当只要一行数据时使用 LIMIT 1,原因:加上 LIMIT 1 可以增加性能。这样一样,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。
为搜索字段建索引,什么情况不适合用索引:当你需要在一篇大的文章中搜索一个词时,如: “WHERE post_content LIKE ‘%apple%'”,索引可能是没有意义的,因为创建索引也是需要占用内存的
在Join表的时候对on条件里相同类型、相同字符集的字段使用索引
千万不要 ORDER BY RAND(),比如需要返回随机打乱顺序的数据。因为MySQL执行RAND()函数会很耗CPU时间
最常见的:避免 SELECT *
永远为每张表设置一个ID,最好是int类型的,因为使用 VARCHAR 类型来当主键会使用得性能下降
尽量使用 ENUM 而不是 VARCHAR,比如性别、状态、民族等有限且固定的值
存值时候尽可能的使用 NOT NULL值
垂直拆分:“垂直分割”是一种把数据库中的表按列变成几张表的方法,这样可以降低表的复杂度和字段的数目,从而达到优化的目的。可以将一些冗余的字段或者不常用的字段拆分出一个表
拆分大的 DELETE 或 INSERT 语句,因为这两个操作是会锁表的,比如删除的量比较大可以加一个limit条件 判断返回是否为0,为0代表已经没有值了停止删除
2)mysql的语句优化,使用什么工具
Explain执行计划
3)mysql的索引分类:B+,hash;什么情况用什么索引
Hash索引只能用于=或<=>的等式比较。而B+适合范围查找,如:id<30或者weight between 100 and 150
如何选择索引列:
在where子句中出现的列,在join子句中出现的列,或者是在ORDER BY 或者GROUP BY子句中出现的数据列。
MySQL只对一下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。
4)mysql的存储引擎有哪些,区别是什么
MyISAM InnoDB MEMORY MERGE TokuDB(说几个常见的吧)
MyISAM:主要特点就是快,没有事务处理操作,也不支持外键操作
InnoDB:是新版本mysql的默认引擎,支持事务处理和外键
MEMORY:数据访问非常快的引擎,默认使用hash索引。一旦服务器关闭表中的数据就会丢失
5)说说事务的特性和隔离级别
原子性:要么发生要么不发生
一致性:失误前后数据必须保证完整性
隔离性:多用户并发访问事务互不干扰
持久性:事务一旦被提交对数据的改变是永久的,即便发生故障
如果不考虑隔离性,事务存在3中并发访问问题。
1)脏读:B事务读取到了A事务尚未提交的数据 ------ 要求B事务要读取A事 务提交的数据
2)不可重复读:一个事务中 两次读取的数据的内容不一致 ----- 要求的是一个事 务中多次读取时数据是一致的 --- unpdate
3)幻读/虚读:一个事务中 两次读取的数据的数量不一致 ----- 要求在一个事务多 次读取的数据的数量是一致的 --insert delete
6)悲观锁和乐观锁的区别,怎么实现
悲观锁:每次拿数据都以为别人会修改,所以每次拿数据时都会上锁
乐观锁:每次拿数据时候都认为别人不会修改,所以不会上锁,但是在更新数据时候会判断在此期间是否有人更新过。
悲观锁实现:开启事务,启用锁机制
乐观锁实现:1.使用版本号2.使用时间戳
五.mq
1)mq的原理是什么:有点大。。都可以说
消息队列技术是分布式应用间交换信息的一种技术,通过消息队列,应用程序可独立地执行--它们不需要知道彼此的位置、或在继续执行前不需要等待接收程序接收此消息。
2)mq如何保证实时性
比如RocketMQ使用长轮询Pull方式,可保证消息非常实时
3)mq的持久化是怎么做的
ActiveMQ提供了插件式的消息存储,主要有有如下几种:
1.AMQ消息存储-基于文件的存储方式,是以前的默认消息存储
2.KahaDB消息存储-提供了容量的提升和恢复能力,是现在的默认存储方式
3.JDBC消息存储-消息基于JDBC存储的
4.Memory消息存储-基于内存的消息存储
六.nosql相关(主要是redis)
1)redis和memcache的区别
1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘
4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10
5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从
6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)
7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复
8、Redis支持数据的备份,即master-slave模式的数据备份。
2)用redis做过什么
1.做过热点数据缓存、
2.设置精准的抢购时间(通过key的过期失效策略)
3.轻松实现计数器(比如点赞)
3)redis是如何持久化的
rdb:原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化
优点是对于灾难恢复而言,rdb可以很轻松的将一个单独的文件转移到其他存储介质上
缺点是如果出现宕机,未来得及存入磁盘的数据将会丢失
aof;原理是将Reids的操作日志以追加的方式写入文件
优点是能更大程度的保证记录的完整性
缺点是对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
可参考: https://www.cnblogs.com/chenliangcl/p/7240350.html
4)redis集群如何同步
主从复制、读写分离
5)redis的数据添加过程是怎样的:哈希槽
6)redis的淘汰策略有哪些
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
7)redis有哪些数据结构
String字符串、List列表、Set集合、Hash散列、Zset有序集合
七.zookeeper
1)zookeeper是什么
分布式的、开源的分布式应用程序协调服务
2)zookeeper哪里用到
结合我实际工作中使用Dubbo框架的情况,Zookeeper主要是做注册中心用
3)zookeeper的选主过程
当leader崩溃或者leader失去大多数的follower,这时zk进入恢复模式,
4)zookeeper是如何保证事务的顺序一致性的
zookeeper采用了递增的事务Id来标识,所有的proposal都在被提出的时候加上了zxid,zxid实际上是一个64位的数字,高32位是epoch用来标识leader是否发生改变,如果有新的leader产生出来,epoch会自增,低32位用来递增计数。当新产生proposal的时候,会依据数据库的两阶段过程,首先会向其他的server发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行
5)分布式锁的实现过程
在zookeeper指定节点(locks)下创建临时顺序节点node_n
获取locks下所有子节点children
对子节点按节点自增序号从小到大排序
判断本节点是不是第一个子节点,若是,则获取锁;若不是,则监听比该节点小的那个节点的删除事件
若监听事件生效,则回到第二步重新进行判断,直到获取到锁
八.linux相关
1)linux常用的命令有哪些
1、cd命令
2、ls命令
3、grep命令
4、find命令 find / -name passwd # 查找文件名为passwd的文件
5、cp命令 cp file1 file2 file3 dir #把文件file1、file2、file3复制到目录dir中
6、mv命令 移动或更名 mv file1 file2 # 把文件file1重命名为file2
7、rm命令 rm -fr dir # 强制删除目录dir中的所有文件
8、ps命令 ps aux # 查看系统所有的进程数据
9、kill命令 kill -9 PID
10、killall命令 killall java
11、tar命令 压缩:tar -jcv -f filename.tar.bz2 要被处理的文件或目录名称 解压:tar -jxv -f filename.tar.bz2 -C 欲解压缩的目录
12、cat命令 cat text | less # 查看text文件中的内容
13、chmod命令 修改权限 chmod 0755 file # 把file的文件权限改变为-rxwr-xr-x
14、vim命令
2)如何获取java进程的pid
grep -ef|grep java
3)如何获取某个进程的网络端口号
netstat -antup //查看已建立的连接进程,所占用的端口。
4)如何实时打印日志
tail -f catalina.out
5)如何统计某个字符串行数
find access_log.20160423.txt | xargs cat | grep .*关键字.*|wc -l
例子说明:统计含"关键字"字符串的总行数
九.设计与思想
1)重构过代码没有?说说经验
比如一些常见的处理代码可以封装成工具、list的为空判断可以用CollectionUtils工具判断、字符串的为空判断可以用StringUtils
2)一千万的用户实时排名如何实现
3)五万人并发抢票怎么实现;
补充:
垂直架构的session解决方案:
1.Nginx的ip_hash。缺点是一台tomcat宕机会导致这台机器的session回话数据会丢失,不符合高可用
2.tomcat的session复制。缺点是每台tomcat都需要保持全局session数据,内存占用严重
3.cookie based。缺点是不安全
4.session集群存储:Nginx负载+spring session+redis
分布式下如何保证ID全局唯一
1.UUID。缺点是不同机器下的高并发场景下可能会重复
2.雪花生成器
3.自己写redis生成:规则:key=前缀+year+day的补位值+hour的补位值 id=redis.incr(key);