面试总结-整理新

基础篇

基本功

1、Hashcode的作用,与 equal 有什么区别?

  a.同样用于鉴定2个对象是否相等的,java集合中有 list 和 set 两类,其中 set不允许元素重复实现,那个这个不允许重复实现的方法,如果用 equal 去比较的话,如果存在1000个元素,你 new 一个新的元素出来,需要去调用1000次 equal 去逐个和他们比较是否是同一个对象,这样会大大降低效率。hashcode实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了,散列到其他地址上。

2、cloneable接口实现原理:只有实现了这个接口,才可以调用Object的clone方法,否则CloneNotSupporteddException

3、comparable与comparator的区别:前者是内部排序,后者是外部排序

4、什么是泛型、为什么要使用以及泛型擦除#

  泛型,即“参数化类型”。
  创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。
  Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。
  类型擦除的主要过程如下:
  1)将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
  2)移除所有的类型参数。

5、Error、Exception区别#

  Error类和Exception类的父类都是throwable类,他们的区别是:
  Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
  Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

6、Object有哪些公用方法

  Object是所有类的父类,任何类都默认继承Object
  clone 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
  equals 在Object中与==是一样的,子类一般需要重写该方法。
  hashCode 该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
  getClass final方法,获得运行时类型
  wait 使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。 wait() 方法一直等待,直到获得锁或者被中断。 wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。
    调用该方法后当前线程进入睡眠状态,直到以下事件发生
    1、其他线程调用了该对象的notify方法。 2、其他线程调用了该对象的notifyAll方法。 3、其他线程调用了interrupt中断该线程。 4、时间间隔到了。 5、此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
  notify 唤醒在该对象上等待的某个线程。
  notifyAll 唤醒在该对象上等待的所有线程。
  toString 转换成字符串,一般子类都有重写,否则打印句柄。

7、Java的四种引用,强弱软虚,用到的场景

  从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
  1.强引用
    最普遍的一种引用方式,如String s = "abc",变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。
  2.软引用(SoftReference)
    用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。
  3.弱引用(WeakReference)
    弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
  4.虚引用(PhantomReference)
    就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。
  虚引用与软引用和弱引用的一个区别在于:
    虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

8、Java对象的生命周期

  答:创建阶段 、 应用阶段 、不可见阶段 、不可达阶段 、收集阶段 、终结阶段、 对象空间重新分配阶段等等,具体参照:Java 对象的生命周期

9、Java类的生命周期:加载------》连接(验证-->准备-->解析)------》初始化------》使用------》卸载

9、一个类对象属性发生改变时,如何让调用者知道:Event事件机制

10、statement和preparedStatement的区别

11、Arraylist的循环删除问题:迭代的时候使用list.remove就会引起ConcurrentModificationException,因为迭代的时候mod是迭代开始时的快照,list.remove时修改了集合的mod,导致迭代时mod快照与集合mod比较不一致就异常了 

集合

 

1、HashMap的实现机制:

  维护一个每个元素是一个链表的数组,而且链表中的每个节点是一个Entry[]键值对的数据结构。
  实现了数组+链表(1.8新增红黑树)的特性,查找快,插入删除也快。
  对于每个key,他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1);
  每个新加入的节点放在链表首,然后该新加入的节点指向原链表首

2、HashMap的源码,实现原理,JDK8中对HashMap做了怎样的优化。:jdk8中hashmap在单链的基础上,增加了单链超过定长(8)坍缩成红黑树,提高了新增和删除节点的效率,提高了读取节点的效率

3、HaspMap扩容是怎样扩容的,为什么都是2的N次幂的大小

6、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?:1.7及以前高并发情况下容易形成环,1.8中也有问题

7、HashMap 的扩容过程:默认初始值16,扩容因子0.75,扩容到原来两倍

4、HashMap冲突:

  友情链接: HashMap冲突的解决方法以及原理分析

8、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?

63、HashMap 的长度为什么是 2 的幂次方?

  通过将 Key 的 hash 值与 length-1 进行 & 运算,实现了当前 Key 的定位,2 的幂次方可以减少冲突(碰撞)的次数,提高 HashMap 查询效率;
  如果 length 为 2 的次幂 则 length-1 转化为二进制必定是 11111……的形式,在于 h 的二进制与操作效率会非常的快,而且空间不浪费;
  如果 length 不是 2 的次幂,比如 length 为 15,则 length-1 为 14,对应的二进制为 1110,在于 h 与操作,最后一位都为 0,而 0001,0011,0101,1001,1011,0111,1101 这几个位置永远都不能存放元素了,空间浪费相当大。
  更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!这样就会造成空间的浪费。

48、HashMap和HashTable区别#
  1)HashTable的方法前面都有synchronized来同步,是线程安全的;HashMap未经同步,是非线程安全的。
  2)HashTable不允许null值(key和value都不可以) ;HashMap允许null值(key和value都可以)。
  3)HashTable有一个contains(Object value)功能和containsValue(Object value)功能一样。
  4)HashTable使用Enumeration进行遍历;HashMap使用Iterator进行遍历。
  5)HashTable中hash数组默认大小是11,增加的方式是old*2+1;HashMap中hash数组的默认大小是16,而且一定是2的指数。
  6)哈希值的使用不同,HashTable直接使用对象的hashCode; HashMap重新计算hash值,而且用与代替求模。

3、HashMap和TreeMap区别:

  友情链接: Java中HashMap和TreeMap的区别深入理解

5、ConcurrentHashMap原理
  ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对Hash表的不同Segment进行的修改。
    ConcurrentHashMap的应用场景是高并发,但是并不能保证线程安全,而同步的HashMap和HashTable的是锁住整个容器,而加锁之后ConcurrentHashMap不需要锁住整个容器,只需要锁住对应的segment就好了,所以可以保证高并发同步访问,提升了效率。 
  ConcurrentHashMap能够保证每一次调用都是原子操作,但是并不保证多次调用之间也是原子操作。
  ConcurrentHashMap是使用了锁分段技术技术来保证线程安全的,锁分段技术:首先把HashMap分成若干个Segmenet,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问
    1.get时,不加锁,先定位到segment然后在找到头结点进行读取操作。而value是volatile变量,所以可以保证在竞争条件时保证读取最新的值,如果读到的value是null,则可能正在修改,那么就调用ReadValueUnderLock函数,加锁保证读到的数据是正确的。
    2.Put时会加锁,一律添加到hash链的头部。
    3.Remove时也会加锁,由于next是final类型不可改变,所以必须把删除的节点之前的节点都复制一遍。
  在JDK8中对这种实现又进行了修改,JDK8中的ConcurrentHashmap基于CAS和TreeBin实现的,不需要对segment或者全局加锁,只需要对单行枷锁(hashCode相同),后边的链表是链表加红黑树。对于单个值的修改使用CAS。

9、LinkedHashMap的原理及应用:LRU算法

11、HashSet与TreeSet的比较
  1.TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值 。
  2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束 。
  3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。
  适用场景分析:
    HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
12、HashMap和ConcurrentHashMap的区别
  1。HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。
  2。ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。
  3。ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。
13、HashTable和ConcurrentHashMap的区别
  它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。

14、极高并发下HashTable和ConcurrentHashMap哪个性能更好,为什么,如何实现的。

15、TreeMap、HashMap、LindedHashMap的区别

  LinkedHashMap可以保证HashMap集合有序,存入的顺序和取出的顺序一致。
  TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。
  HashMap不保证顺序,即为无序的,具有很快的访问速度。 HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null。 HashMap不支持线程的同步。

  我们在开发的过程中使用HashMap比较多,在Map中在Map 中插入、删除和定位元素,HashMap 是最好的选择。
  但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
  如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列。

 

10、Arraylist与LinkedList的比较
  1.ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
  2.因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
  3.LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。
  4.因为LinkedList要移动指针,所以查询操作性能比较低。
  适用场景分析:
    当需要对数据进行随机访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
11、ArrayList与Vector的比较
  1.Vector的方法都是同步的,是线程安全的,而ArrayList的方法不是,由于线程的同步必然要影响性能。因此,ArrayList的性能比Vector好。
  2.当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样。ArrayList就有利于节约内存空间。
  3.大多数情况不使用Vector,因为性能不好,但是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性。
  4.Vector可以设置增长因子,而ArrayList不可以。
  适用场景分析:
    1.Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
    2.如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。

12、CopyOnWriteArrayList : 写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,然后在新的容器里面写,写完之后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,所以可以进行并发的读,但这是一种弱一致性的策略。
  使用场景:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。

14、Arrays和Collections 对于sort的不同实现原理?

  1。Arrays.sort()
    该算法是一个经过调优的快速排序,此算法在很多数据集上提供N*log(N)的性能,这导致其他快速排序会降低二次型性能。
  2。Collections.sort()
    该算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素效益高子列表中的最低元素,则忽略合并)。此算法可提供保证的N*log(N)的性能,此实现将指定列表转储到一个数组中,然后再对数组进行排序,在重置数组中相应位置处每个元素的列表上进行迭代。

15、说说常见的集合有哪些吧?

  Map 接口和 Collection 接口是所有集合框架的父接口:
  Collection 接口的子接口包括:Set 接口和 List 接口;
  Map 接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等;
  Set 接口的实现类主要有:HashSet、TreeSet、LinkedHashSet 等;
  List 接口的实现类主要有:ArrayList、LinkedList、Stack 以及 Vector 等。

65、List、Set 和 Map 的初始容量和加载因子

  1. List
    ArrayList 的初始容量是 10;加载因子为 0.5; 扩容增量:原容量的 0.5 倍 +1;一次扩容后长度为 16。
    Vector 初始容量为 10,加载因子是 1。扩容增量:原容量的 1 倍,如 Vector 的容量为 10,一次扩容后是容量为 20。
  2. Set
    HashSet,初始容量为 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashSet 的容量为 16,一次扩容后容量为 32
  3. Map
    HashMap,初始容量 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashMap 的容量为 16,一次扩容后容量为 32

67、Java 集合的快速失败机制 “fail-fast”
  它是 java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。
  例如 :假设存在两个线程(线程 1、线程 2),线程 1 通过 Iterator 在遍历集合 A 中的元素,在某个时候线程 2 修改了集合 A 的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生 fail-fast 机制。
  原因: 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变 modCount 的值。

  每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。
  解决办法:
  在遍历过程中,所有涉及到改变 modCount 值得地方全部加上 synchronized;
  使用 CopyOnWriteArrayList 来替换 ArrayList。

 

多线程

1、创建线程的方式及实现:Thread,Runnable,Callable

62、 wait/notify/notifyAll⽅法需不需要被包含在synchronized块中?这是为什 么?:需要,否则会抛出异常

81.、wait和sleep的区别
  1。sleep()方法是属于Thread类中的,而wait()方法,则是属于Object类中的。
  2。sleep()方法导致了程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。所以在调用sleep()方法的过程中,线程不会释放对象锁。
  3。调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

68、Thread 类中的start() 和 run() 方法有什么区别?

 

72、 如何避免死锁?

73、Java中活锁和死锁有什么区别?饿死?:活锁是都让别人去获取锁,结果都不获取锁,解决方式为只让一个人释放资源 | 死锁是都自己去获取锁,结果都获取不到锁 | 饿死是任务一直获取不到资源,解决为采用队列 

  

2、CountDownLatch,CyclicBarrier, Semaphore,Exchanger的原理

48、CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别?:前者是等所有线程完成后另外一个线程做一件事情,后者是等所有线程完成后一起做一件事情

35、怎么实现所有线程在等待某个事件的发生才会去执行?:CyclicBarrier

4、ThreadLocal(线程变量副本)

  Thread包含一个Map结构,key就是ThreadLocal变量,value就是变量值|使用时注意线程池情况下,线程被复用的问题
  ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。
  Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。

5、Volatile和Synchronized四个不同点:

  1。粒度不同,前者针对变量 ,后者锁对象和类
  2。syn阻塞,volatile线程不阻塞
  3。syn保证三大特性(可见性,原子性,有序性),volatile不保证原子性
  4。syn编译器优化,volatile不优化

6、同步,异步,阻塞,非阻塞

  同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。
  异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。
  阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。
  非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作,非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。

93、Volatile的特征:
    A、禁止指令重排(有例外)
    B、可见性
  Volatile的内存语义:
    当写一个volatile变量时,JMM会把线程对应的本地内存中的共享变量值刷新到主内存。
    当读一个volatile变量时,JMM会把线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量。
  Volatile的重排序
    1。当第二个操作为volatile写操做时,不管第一个操作是什么(普通读写或者volatile读写),都不能进行重排序。这个规则确保volatile写之前的所有操作都不会被重排序到volatile之后;
    2。当第一个操作为volatile读操作时,不管第二个操作是什么,都不能进行重排序。这个规则确保volatile读之后的所有操作都不会被重排序到volatile之前;
    3。当第一个操作是volatile写操作时,第二个操作是volatile读操作,不能进行重排序。
  这个规则和前面两个规则一起构成了:两个volatile变量操作不能够进行重排序;

  除以上三种情况以外可以进行重排序。
  比如:
    1。第一个操作是普通变量读/写,第二个是volatile变量的读;
    2。第一个操作是volatile变量的写,第二个是普通变量的读/写;

31、synchronized 的实现原理以及锁优化? 

61、synchronized关键字锁住的是什么东⻄?在字节码中是怎么表示的?在内 存中的对象上表现为什么?

138、synchronized 关键字:
  底层实现:
  进入时,执行 monitorenter,将计数器 +1,释放锁 monitorexit 时,计数器-1;
  当一个线程判断到计数器为 0 时,则当前锁空闲,可以占用;反之,当前线程进入等待状态。
  含义:(monitor 机制)
  Synchronized 是在加锁,加对象锁。对象锁是一种重量锁(monitor),synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。
  该关键字是一个几种锁的封装。

139、synchronized锁膨胀原理:自旋锁?无锁->偏向锁->轻量级锁(cas)->重量级锁

32、volatile 的实现原理?

33、双检锁DCL问题:线程安全问题,其他线程获取到的单例实例可能还未初始化完(happens-before原理引起的),解决方案为单例实例改为volatile,或者不要采用懒加载,或者用枚举,或者用holder模式

36、CAS?CAS 有什么缺陷,如何解决?:ABA问题,AtomicStampedReference通过版本号来解决

37、ABA 问题:AtomicStampedReference通过版本号来解决

37、synchronized 和 lock 有什么区别?

74、Java中synchronized 和 ReentrantLock 有什么不同?

41、AQS

49、LockSupport工具

50、Condition接口及其实现原理

 

76、 如何在Java中创建Immutable对象?:final,集合类的unmodified。。。

 

94、内存屏障/内存栅栏
  内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。(也就是让一个CPU处理单元中的内存状态对其它处理单元可见的一项技术。)
  内存屏障可以被分为以下几种类型:
    LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
    StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
    LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
    StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。
  在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。
  内存屏障阻碍了CPU采用优化技术来降低内存操作延迟,必须考虑因此带来的性能损失。为了达到最佳性能,最好是把要解决的问题模块化,这样处理器可以按单元执行任务,然后在任务单元的边界放上所有需要的内存屏障。采用这个方法可以让处理器不受限的执行一个任务单元。合理的内存屏障组合还有一个好处是:缓冲区在第一次被刷后开销会减少,因为再填充改缓冲区不需要额外工作了。

 

95、happens-before原则

 

96、Java 线程有哪些状态,这些状态之间是如何转化的?

      

  1。新建(new):新创建了一个线程对象。
  2。可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
  3。运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
  4。阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
    (一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
    (二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
    (三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
  5。死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

41、Blocked和Waiting的区别 

42、Java 内存模型?

 

38、HashMap 的并发问题?

40、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?

43、如何保证多线程下 i++ 结果正确?:加锁,或者用AtomicInteger 

52、分段锁的原理,锁力度减小的思考

53、八种阻塞队列以及各个阻塞队列的特性

55. 多个线程同时读写,读线程的数量远远⼤于写线程,你认为应该如何解决 并发的问题?你会选择加什么样的锁?:读写锁

51、Fork/Join框架的理解

134、如何指定多个线程的执行顺序?
  解析:面试官会给你举个例子,如何让 10 个线程按照顺序打印 0123456789?(写代码实现)
  答:设定一个 orderNum,每个线程执行结束之后,更新 orderNum,指明下一个要执行的线程。并且唤醒所有的等待线程。
  在每一个线程的开始,要 while 判断 orderNum 是否等于自己的要求值!!不是,则 wait,是则执行本线程。

136、多线程产生死锁的 4 个必要条件?
  互斥条件:一个资源每次只能被一个线程使用;
  请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放;
  不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺;
  循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

137、如何避免死锁?
  指定获取锁的顺序,举例如下:
  比如某个线程只有获得 A 锁和 B 锁才能对某资源进行操作,在多线程条件下,如何避免死锁?
  获得锁的顺序是一定的,比如规定,只有获得 A 锁的线程才有资格获取 B 锁,按顺序获取锁就可以避免死锁

138、悲观锁和乐观锁的区别,怎么实现
  悲观锁:一段执行逻辑加上悲观锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。|select for update
  乐观锁:一段执行逻辑加上乐观锁,不同线程同时执行时,可以同时进入执行,在最后更新数据的时候要检查这些数据是否被其他线程修改了(版本和执行初是否相同),没有修改则进行更新,否则放弃本次操作。|版本号

 

6、线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程
  第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  第三:提高线程的可管理性。
  常用线程池:ExecutorService 是主要的实现类,其中常用的有 Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。

44、线程池的种类,区别和使用场景?

46、线程池如何调优,最大数目如何确认?:有个公式

45、分析线程池的实现原理和线程的调度过程?

59、线程池内的线程如果全部忙,提交⼀个新的任务,会发⽣什么?队列全部塞满了之后,还是忙,再提交会发⽣什么?

7、说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行)

7、线程池原理:

  等待任务队列和工作集:

  

  线程池的主要状态锁:

  

  线程池的存活时间和大小:

  

  ThreadPoolExecutor 的内部工作原理

   1.如果当前池大小 poolSize 小于 corePoolSize ,则创建新线程执行任务。
   2.如果当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列
   3.如果当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则创建新线程执行任务。
   4.如果当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略来处理该任务。
   5.线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在 keepAliveTime 里等不到新的任务了,那么线程就会退出。

 

 

60. Tomcat本身的参数你⼀般会怎么调整?:调整线程池大小

 

 

 

 

JVM

1、Java内存模型:
  Java虚拟机规范中将Java运行时数据分为六种。
  1.程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。
  2.Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。
  3.本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。
  4.Java堆:所有线程共享的一块内存区域,对象实例几乎都在这分配内存。
  5.方法区:各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。
  6.运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用

22、OOM错误,stackoverflow错误,permgen space错误

2、“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”
  在什么时候:
  1.新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存。在某次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去。
  2.大对象以及长期存活的对象直接进入老年区。
  3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。

  对什么东西:从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象。
  做什么: 新生代:复制清理; 老年代:标记-清除和标记-压缩算法; 永久代:存放Java中的类和加载类的类加载器本身。
  GC Roots都有哪些: 1. 虚拟机栈中的引用的对象 2. 方法区中静态属性引用的对象,常量引用的对象 3. 本地方法栈中JNI(即一般说的Native方法)引用的对象。

3、类加载器工作机制:
  1。装载:将Java二进制代码导入jvm中,生成Class文件。
  2。连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用
  3。初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。
  双亲委派模型:类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。

16、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?:有,Thread.currentThread可以设置classloader,以及osgi

25. JAVA类加载器包括⼏种?它们之间的⽗⼦关系是怎么样的?双亲委派机 制是什么意思?有什么好处?

54、Java类加载的过程。

55、双亲委派模型的过程以及优势。 

64、Java类加载器及如何加载类(双亲委派)#
  阅读文章:
  https://www.ibm.com/developerworks/cn/java/j-lo-classloader/(推荐)
  http://blog.csdn.net/zhoudaxia/article/details/35824249

65、Class.forName 和 ClassLoader.loadClass的区别 

 

4、Java的四种引用,强弱软虚,以及用到的场景
  a.强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。
  b.软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
  c.弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。
  d.虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

5、JAVA 中堆和栈的区别,说下java 的内存机制
  a.基本数据类型比变量和对象的引用都是在栈分配的
  b.堆内存用来存放由new创建的对象和数组
  c.类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中
  d.实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”,实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存
  e.局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放

6、JAVA多态的实现原理
  a.抽象的来讲,多态的意思就是同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
  b.实现的原理是动态绑定,程序调用的方法在运行期才动态绑定,追溯源码可以发现,JVM 通过参数的自动转型来找到合适的办法。

9、数组在内存中如何分配:简单类型数组在栈上分配,引用类型在堆上分配

9、Java内存模型 : http://blog.csdn.net/zhaojw_420/article/details/70477903

14、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?

18、JVM垃圾回收机制,何时触发MinorGC等操作:eden区无法为对象分配空间

19、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的

 

45、JVM方法栈的工作过程,方法栈和本地方法栈有什么区别。

46、JVM的栈中引用如何和堆中的对象产生关联。

44、JVM的内存结构。 

50、eden survivor区的比例,为什么是这个比例,eden survivor的工作过程。

 

49、标记清除和标记整理算法的理解以及优缺点。

69、垃圾回收算法有哪些?
  引用计数 :原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题;
  标记-清除 :此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除;此算法需要暂停整个应用,同时,会产生内存碎片;
  复制算法 :此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中;此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片” 问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间;
  标记-整理 :此算法结合了 “标记-清除” 和 “复制” 两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 “压缩” 到堆的其中一块,按顺序排放。此算法避免了 “标记-清除” 的碎片问题,同时也避免了 “复制” 算法的空间问题。

48、GC的常见算法,CMS以及G1的垃圾回收过程,CMS的各个阶段哪两个是Stop the world的,CMS会不会产生碎片,G1的优势。

20、各种回收器,各自优缺点,重点CMS、G1

21、各种回收算法

53、Java是否可以GC直接内存。:不可以,是在ByteBuffer分配内存时设置了清理器

58、Java有没有主动触发GC的方式(没有)。

63、Java内存管理及回收算法#
  阅读这篇文章:http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html

70、root 搜索算法中,哪些可以作为 root?
  被启动类(bootstrap 加载器)加载的类和创建的对象;
  JavaStack 中的引用的对象 (栈内存中引用的对象);
  方法区中静态引用指向的对象;
  方法区中常量引用指向的对象;
  Native 方法中 JNI 引用的对象。

71、GC 什么时候开始?
  GC 经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个 Eden 区和两个 Survivor 区。
  对象优先在 Eden 中分配,当 Eden 中没有足够空间时,虚拟机将发生一次 Minor GC,因为 Java 大多数对象都是朝生夕灭,所以 Minor GC 非常频繁,而且速度也很快;
  Full GC,发生在老年代的 GC,当老年代没有足够的空间时即发生 Full GC,发生 Full GC 一般都会有一次 Minor GC。
  大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个;XX:PretenureSizeThreadhold 参数,令大于这个参数值的对象直接在老年代中分配,避免在 Eden 区和两个 Survivor 区发生大量的内存拷贝;
  发生 Minor GC 时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次 Full GC,如果小于,则查看 HandlePromotionFailure 设置是否允许担保失败,如果允许,那只会进行一次 Minor GC,如果不允许,则改为进行一次 Full GC。

 

56、常用的JVM调优参数。

68、类似-Xms、-Xmn 这些参数的含义:
  堆内存分配:
    JVM 初始分配的内存由-Xms 指定,默认是物理内存的 1/64;
    JVM 最大分配的内存由-Xmx 指定,默认是物理内存的 1/4;
    默认空余堆内存小于 40% 时,JVM 就会增大堆直到-Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制;
    因此服务器一般设置-Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。
  非堆内存分配:
    JVM 使用-XX:PermSize 设置非堆内存初始值,默认是物理内存的 1/64;
    由 XX:MaxPermSize 设置最大非堆内存的大小,默认是物理内存的 1/4;
    -Xmn2G:设置年轻代大小为 2G;
    -XX:SurvivorRatio,设置年轻代中 Eden 区与 Survivor 区的比值。

29. 1.8之后Perm Space有哪些变动? MetaSpace⼤⼩默认是⽆限的么? 还是你们会通过什么⽅式来指定⼤⼩?:不是,默认20M,XX:MetaspaceSize=200m;-XX:MaxMetaspaceSize=256m

31. StackOverFlow异常有没有遇到过?⼀般你猜测会在什么情况下被触发?如何指定⼀个线程的堆栈⼤⼩?⼀般你们写多少?:xss来指定

57、dump文件的分析。

59、内存溢出和内存泄漏的区别#
  内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory。
  内存泄漏是指分配出去的内存不再使用,但是无法回收。

60、Java内存模型及各个区域的OOM,如何重现OOM#
  这部分内容很重要,详细阅读《深入理解Java虚拟机》,也可以详细阅读这篇文章http://hllvm.group.iteye.com/group/wiki/2857-JVM

  线程共享部分:方法区,又名永久代,无GC(常量池内存不足OOM)。堆区,分配时内存不足则OOM。

  线程私有部分:虚拟机栈,线程请求栈深度超过阈值则SOF,分配时内存不足OOM。本地方法栈,同虚拟机栈一样。程序计数器,没有OOM。

  直接内存,空间不足则OOM  

 

61、出现OOM如何解决#
  一. 可通过命令定期抓取heap dump或者启动参数OOM时自动抓取heap dump文件。
  二. 通过对比多个heap dump,以及heap dump的内容,分析代码找出内存占用最多的地方。
  三. 分析占用的内存对象,是否是因为错误导致的内存未及时释放,或者数据过多导致的内存溢出。

 

15、JVM 出现 fullGC 很频繁,怎么去线上排查问题?:

24. 你知道哪些或者你们线上使⽤什么GC策略? 它有什么优势,适⽤于什么 场景?

28. 你有没有遇到过OutOfMemory问题?你是怎么来处理这个问题的?处理过程中有哪些收获?

30. Jstack是⼲什么的? Jstat呢? 如果线上程序周期性地出现卡顿,你怀疑可能是gc导致的,你会怎么来排查这个问题?线程⽇志⼀般你会看其中的什么 部分?:jstack查看线程堆栈|查看fullgc/minor时间和频率|线程日志一般看blocked-->waiting-->timed_waiting

35、请写一段栈溢出、堆溢出的代码
  递归调用可以导致栈溢出
  不断创建对象可以导致堆溢出

 

 

 

 

 

 

NIO

2、BIO、NIO和AIO的区别
  Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
  Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
  Java AIO : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
  NIO比BIO的改善之处是把一些无效的连接挡在了启动线程之前,减少了这部分资源的浪费(因为我们都知道每创建一个线程,就要为这个线程分配一定的内存空间)
  AIO比NIO的进一步改善之处是将一些暂时可能无效的请求挡在了启动线程之前,比如在NIO的处理方式中,当一个请求来的话,开启线程进行处理,但这个请求所需要的资源还没有就绪,此时必须等待后端的应用资源,这时线程就被阻塞了。
  适用场景分析:
    BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解,如之前在Apache中使用。
    NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持,如在 Nginx,Netty中使用。
    AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持,在成长中,Netty曾经使用过,后来放弃。

 3、Java IO与NIO

  NIO是为了弥补IO操作的不足而诞生的,NIO的一些新特性有:非阻塞I/O,选择器,缓冲以及管道。管道(Channel),缓冲(Buffer) ,选择器( Selector)是其主要特征。
  概念解释
    Channel——管道实际上就像传统IO中的流,到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象。一个 Buffer 实质上是一个容器对象。
    Selector——选择器用于监听多个管道的事件,使用传统的阻塞IO时我们可以方便的知道什么时候可以进行读写,而使用非阻塞通道,我们需要一些方法来知道什么时候通道准备好了,选择器正是为这个需要而诞生的。

    每一种基本 Java 类型都有一种缓冲区类型:
    ByteBuffer——byte
    CharBuffer——char
    ShortBuffer——short
    IntBuffer——int
    LongBuffer——long
    FloatBuffer——float
    DoubleBuffer——double
  NIO和传统的IO有什么区别呢?
    IO是面向流的,NIO是面向块(缓冲区)的:
      IO面向流的操作一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。,导致了数据的读取和写入效率不佳。
      NIO面向块的操作在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多,同时数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。通俗来说,NIO采取了“预读”的方式,当你读取某一部分数据时,他就会猜测你下一步可能会读取的数据而预先缓冲下来。
    IO是阻塞的,NIO是非阻塞的:
      对于传统的IO,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。
      而对于NIO,使用一个线程发送读取数据请求,没有得到响应之前,线程是空闲的,此时线程可以去执行别的任务,而不是像IO中那样只能等待响应完成。
  NIO和IO适用场景:
    NIO是为弥补传统IO的不足而诞生的,但是尺有所短寸有所长,NIO也有缺点,因为NIO是面向缓冲区的操作,每一次的数据处理都是对缓冲区进行的,那么就会有一个问题,在数据处理之前必须要判断缓冲区的数据是否完整或者已经读取完毕,如果没有,假设数据只读取了一部分,那么对不完整的数据处理没有任何意义。所以每次数据处理之前都要检测缓冲区数据。
  那么NIO和IO各适用的场景是什么呢?
    如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,这时候用NIO处理数据可能是个很好的选择。
    而如果只有少量的连接,而这些连接每次要发送大量的数据,这时候传统的IO更合适。使用哪种处理数据,需要在数据的响应等待时间和检查缓冲区数据的时间上作比较来权衡选择。
  通俗解释,最后,对于NIO和传统IO
  有一个网友讲的生动的例子:

  以前的流总是堵塞的,一个线程只要对它进行操作,其它操作就会被堵塞,也就相当于水管没有阀门,你伸手接水的时候,不管水到了没有,你就都只能耗在接水(流)上。
  nio的Channel的加入,相当于增加了水龙头(有阀门),虽然一个时刻也只能接一个水管的水,但依赖轮换策略,在水量不大的时候,各个水管里流出来的水,都可以得到妥善接纳,这个关键之处就是增加了一个接水工,也就是Selector,他负责协调,也就是看哪根水管有水了的话,在当前水管的水接到一定程度的时候,就切换一下:临时关上当前水龙头,试着打开另一个水龙头(看看有没有水)。
  当其他人需要用水的时候,不是直接去接水,而是事前提了一个水桶给接水工,这个水桶就是Buffer。也就是,其他人虽然也可能要等,但不会在现场等,而是回家等,可以做其它事去,水接满了,接水工会通知他们。
  这其实也是非常接近当前社会分工细化的现实,也是统分利用现有资源达到并发效果的一种很经济的手段,而不是动不动就来个并行处理,虽然那样是最简单的,但也是最浪费资源的方式。

4、Netty的Reactor模型

 

 

 

 

算法

20、一致性Hash算法,一致性Hash算法的应用:

  我们把服务器集群分成n段,每个服务器负责一段路由key。

  如果其中一台挂了,只是影响这一段路由key失效,不影响其他。

  如果要加一台机器的话,我们加在其中一个分段中,那么这个分段也只有一小段路由key会失效,另外一小段不影响。

  这样就在很大程度上减小了影响范围,主要应用在缓存集群中

18、B+树:树结构就是索引结构,采用B+树跟磁盘有关,磁盘会预读树结点附近的数据,这样就会很容易命中需要查询的数据,并且减少了磁盘IO次数

28、如何判断一个单链表是否有环:采用list来存放所有元素,有重复则存在环|采用不同步长的指针来遍历,步长较长的会赶上较短的

29、红黑树:因为红黑树的结构可以用很少的旋转开销就能完成插入和删除,减小了红黑树结构的维护成本

  参考:https://blog.csdn.net/mmshixing/article/details/51692892

 

其他 

104、三次握手、四次挥手示意图:

  握手阶段:C告诉S我要链接--->S回答C说已经准备好了--->C回答S说我收到你准备好了

  挥手阶段:C告诉S我要断开--->S回答C说我准备断开了,但是等我发送完数据--->S告诉C说我发完最后一波数据了--->C回答S说我收到你最后一波数据

  挥手阶段比握手阶段多了一个服务端发送最后数据的过程

  详解:https://blog.csdn.net/qzcsu/article/details/72861891

总共有四种状态:主动建立连接、主动断开连接、被动建立连和被动断开连接
  两两组合还是 4 种组合:
  1.主动建立连接、主动断开连接会经历的状态:
  SYNC_SENT——ESTABLISHED—-FIN_WAIT_1—-FIN_WAIT_2—-TIME_WAIT
  2.主动建立连接、被动断开连接会经历的状态:
  SYNC_SENT——ESTABLISHED—-CLOSE_WAIT—-LAST_ACK
  3.被动建立连接、主动断开连接会经历的状态:
  LISTEN—-SYN_RCVD—-ESTABLISHED—-FIN_WAIT_1—-FIN_WAIT_2—-TIME_WAIT
  4.被动建立连接、被动断开连接会经历的状态:
  LISTEN—-SYN_RCVD—-ESTABLISHED—-CLOSE_WAIT—-LAST_ACK

105、滑动窗口机制
  由发送方和接收方在三次握手阶段,互相将自己的最大可接收的数据量告诉对方。也就是自己的数据接收缓冲池的大小。这样对方可以根据已发送的数据量来计算是否可以接着发送。
在处理过程中,当接收缓冲池的大小发生变化时,要给对方发送更新窗口大小的通知。

 

 

 

核心篇

数据存储------(死锁,索引,事务,优化,分库分表,读写分离)

6、MySQL 遇到的死锁问题

 参考:http://www.kissyu.org/2017/02/19/%E8%AE%B0%E5%BD%95%E4%B8%80%E6%AC%A1Mysql%E6%AD%BB%E9%94%81%E6%8E%92%E6%9F%A5%E8%BF%87%E7%A8%8B/

29、悲观锁、乐观锁:版本号检测为乐观锁,其他为悲观锁

61、产生死锁的必要条件:互斥条件|请求与保持条件|不剥夺条件|循环等待条件
  参考http://blog.sina.com.cn/s/blog_5e3604840100ddgq.html

62、死锁预防:确保获取锁的顺序一致
  参考http://blog.sina.com.cn/s/blog_5e3604840100ddgq.html

84、数据库中的锁有哪几种?:独占锁、排他锁以及更新锁。

85、如何解除死锁状态:查看在锁的事务--->kill线程id

87、MyISAM 和 InnoDB 的区别有哪些?:MyISAM 表不支持事务、不支持行级锁、不支持外键。 InnoDB 表支持事务、支持行级锁、支持外键

54、各个数据库引擎区别:http://www.jb51.net/article/38004.htm

 

1、MySQL 索引使用的注意事项

8、数据库索引的原理:B+树

10、索引:B+,B-,全文索引

  Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。
  常用的数据结构是B+Tree,每个叶子节点不但存放了索引键的相关信息还增加了指向相邻叶子节点的指针,这样就形成了带有顺序访问指针的B+Tree,做这个优化的目的是提高不同区间访问的性能。
11、什么时候使用索引:
    经常出现在group by,order by和distinc关键字后面的字段
    经常与其他表进行连接的表,在连接字段上应该建立索引
    经常出现在Where子句中的字段
    经常出现用作查询选择的字段

23、mysql的索引分类:B+,hash;什么情况用什么索引:hash索引不支持范围查询

30、组合索引,最左原则

31、mysql 的表锁、行锁、页锁

36、如果查询很慢,你会想到的第⼀个⽅式是什么?索引是⼲嘛的?:加索引,索引是为数据保持了一个有序的映射,类似于TreeMap

37、如果建了⼀个单列索引,查询的时候查出2列,会⽤到这个单列索引吗?:会

38、如果建了⼀个包含多个列的索引,查询的时候只⽤了第⼀列,能不能⽤上 这个索引?查三列呢?:最左原则

40、怎么看是否⽤到了某个索引?:explain执行计划看type

52、MySQL为什么使用B+树作为索引?:因为B+树可以预读,减少磁盘IO次数,提高数据查询速度

  参考:https://blog.csdn.net/bigtree_3721/article/details/73650601

55、索引的使用注意事项:https://www.cnblogs.com/zlingh/p/3883716.html 

58、索引的优缺点,什么字段上建立索引:order by, where ,group by,distinct,join等字段

69、数据库索引的实现(B+树介绍、和B树、R树区别)#

71、数据库索引的优缺点以及什么时候数据库索引失效#:not in,!=不会命中索引

72、当数据表中A、B字段做了组合索引,那么单独使用A或单独使用B会有索引效果吗?(使用like查询如何有索引效果)
  答:A、B两字段做组合索引的时候,谁在前面,谁在后面,如果A在前,那么单独使用A会有索引效果,单独使用B则没有,反之亦然。同理,使用like模糊查询时,如果只是使用前面%,那么有索引效果,如果使用双%号匹配,那么则无索引效果

86、数据库的索引有什么作用?(必考) 底层数据结构是什么,为什么使用这种数据结构?

  索引 是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息;
  底层数据结构是 B+ 树;
  使用 B+ 树的原因:查找速度快、效率高,在查找的过程中,每次都能抛弃掉一部分节点,减少遍历个数。( 此时,你应该在白纸上画出什么是 B+ 树 )
87、聚簇索引和非聚簇索引的区别?

 

25、说说事务的特性和隔离级别;

  作为单个逻辑工作单元执行的一系列操作,满足四大特性:
    原子性(Atomicity):事务作为一个整体被执行 ,要么全部执行,要么全部不执行;
    一致性(Consistency):保证数据库状态从一个一致状态转变为另一个一致状态;
    隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行;
    持久性(Durability):一个事务一旦提交,对数据库的修改应该永久保存。

   Mysql的事物隔离级别?

    Read Uncommitted(读取未提交内容)

    Read Committed(读取提交内容)

    Repeatable Read(可重读)

    Serializable(可串行化)

83、事务的并发问题有哪几种?

  丢失更新、脏读、不可重复读以及幻读。

85、事务的隔离级别有哪几种?MySQL 事务默认隔离级别是哪个?
  答:读未提交、读已提交、可重复读和序列化。可重复读。

 

12、MySQL数据库优化总结

13、MYSQL 优化常用方法

53、mysql优化经验

  1。对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
  2。应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
  3。尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
  4。任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
  5。避免频繁创建和删除临时表,以减少系统表资源的消耗。诸如此类,等等等等......

57、常见的数据库优化手段

77、一条sql执行过长的时间,你如何优化,从哪些方面?
  1。查看sql是否涉及多表的联表或者子查询,如果有,看是否能进行业务拆分,相关字段冗余或者合并成临时表(业务和算法的优化)
  2。涉及链表的查询,是否能进行分表查询,单表查询之后的结果进行字段整合
  3。如果以上两种都不能操作,非要链表查询,那么考虑对相对应的查询条件做索引。加快查询速度
  4。针对数量大的表进行历史表分离(如交易流水表)
  5。数据库主从分离,读写分离,降低读写针对同一表同时的压力,至于主从同步,mysql有自带的binlog实现 主从同步
  6。explain分析sql语句,查看执行计划,分析索引是否用上,分析扫描行数等等
  7。查看mysql执行日志,看看是否有其他方面的问题

 

28、mysql分页有什么优化

11、limit 20000 加载很慢怎么解决:采用id排序,通过id来限制范围

45. 你们的数据库单表数据量是多少?⼀般多⼤的时候开始出现查询性能急剧下降?:1000万

46、mysql的最大写入速度?:7500(4G内存+20G硬盘+1个CPU,4核)

  

 

3、说说分库与分表设计:用户中心,通过用户id(手机号索引表,邮箱索引表)路由打散到4个DB,每个DB把表切分成8张分表,一共有4×8=32张表

4、分库与分表带来的分布式困境与应对之策:分布式事务,子查询,关联查询,分页查询|分布式事务中间件(分布式事务),把所有分库分表数据同步汇总到一个库,在这个库上进行操作(分页查询),拆分为单表查询(子查询,关联查询)

12、选择合适的分布式主键方案

  基于数据库方案:auto_increment | 多个库相同步长间隔auto_increment | 数据库单条记录+ID批量生成服务 | 数据库单条记录+ID批量生成服务+灾备模式 | 数据库单条记录+去中心化ID批量生成服务

  基于中间件方案:Tair/Redis原子操作|

  本地化方案:UUID | 当前时间 | snowflake

14、ObjectId 规则

13、选择合适的数据存储方案

47. 读写分离是怎么做的?你认为中间件会怎么来操作?这样操作跟事务有什么关系?:mysql主从复制,读全部打到从,写全部打到主|中间件会解析sql分析读写操作|主从同步延迟引起的事务一致性问题?

14. 分库分表有没有做过?线上的迁移过程是怎么样的?如何确定数据是正 确的?:在老库上挂上精卫,订阅精卫任务将数据写入分库分表

59、数据库连接池。:原理?

65、.数据库连接池的原理#
参考http://blog.csdn.net/shuaihj/article/details/14223015

74、简单说说数据库集群和负载均衡、分布式(我不懂这块)

 

 

16、倒排索引

17、聊聊 ElasticSearch 使用场景

 80、MySQL 和 MongoDB 的区别有哪些?如何选择?

 81、MongoDB 的优缺点有哪些?

 

 

缓存

11、Redis数据结构:String,Hash,List,Set,Sorted Set

 2、Redis 内部结构

7、Redis 为什么是单线程的:缓存主要是io密集型,对cpu需求不大,所以单线程已经满足要求

20、Redis用过哪些数据数据,以及Redis底层怎么实现

 

4、Redis 持久化机制:rdb和aof

6、Redis 集群方案与实现:

8、缓存奔溃:缓存过期,全部穿透到后端的情况,可以种一个缓存(60s)和一个缓存标识(30s),访问的时候先访问缓存标识,发现过期后触发异步更新缓存,并返回当前60s的缓存

9、缓存降级:丢卒保帅,一般错误-->警告-->错误-->严重错误

15、redis集群如何同步:数据复制,slave发起请求,master push数据

16、redis的数据添加过程是怎样的:哈希槽

17、redis的淘汰策略有哪些:volatile-lru,volatile-ttl,volatile-random,allkeys-lru,allkeys-random,no-enviction

21、Redis缓存穿透,缓存雪崩:没有命中缓存,方案有加锁穿透并种缓存,异步种全量缓存,布隆过滤器

22、如何使用Redis来实现分布式锁:setnx

24、Redis持久化的几种方式,优缺点是什么,怎么实现的:aof(每个操作一个脚本),rdb(定时全两快照)

23、Redis的并发竞争问题,以及如何解决:乐观锁,watch

25、Redis的缓存失效策略:定期删除(随机检查删除)+ 惰性删除(get的时候再去检查删除)+ 内存淘汰机制(lru)

26、Redis集群,高可用,原理:sentinal

27、Redis缓存分片:客户端分片(jedis),基于代理的分片(codis),路由查询(redis cluster)

  参考:https://www.jianshu.com/p/14835303b07e

31、渐进式rehash过程?:同时持有两个hash,逐渐迁移

35、事务与事件:事件IO多路复用,reactor模型

36、主从复制:

37、启动过程

38、集群

39、redis哨兵机制

40、redis高可用方案:哨兵机制

42、redis的两个持久化策略:http://blog.csdn.net/u010785685/article/details/52366977

43、redis如何事务支持:https://www.cnblogs.com/kyrin/p/5967620.html
44、redis哨兵机制:http://blog.csdn.net/zbw18297786698/article/details/52891695
45、redis集群方案:https://www.zhihu.com/question/21419897
46、redis主从同步策略:http://blog.csdn.net/sk199048/article/details/50725369
46、redis是单线程的么,所有的工作都是单线程么。
47、redis如何存储一个String的:char数组
49、redis的哨兵模式,一个key值如何在redis集群中找到存储在哪里。

  

3、聊聊 Redis 使用场景:缓存,队列

13、用redis做过什么:cache,队列

12、redis和memcache的区别:数据结构不一样|redis单线程|mc读性能更高

10、使用缓存的合理性问题:

 

 

消息队列

2、消息的重发补偿解决思路

3、消息的幂等性解决思路

4、消息的堆积解决思路

5、自己如何实现消息队列

6、如何保证消息的有序性:根据业务id确定路由到哪个broker,保证同一个业务id路由到同一个broker

7、mq的原理是什么:有点大。。都可以说;

8、mq如何保证实时性;

9、mq的持久化是怎么做的;

 

1、消息队列的使用场景:解耦,异步,削峰|发邮件,发短信

 

 

框架篇

Spring

9、如何自定义注解实现功能:声明注解,注解解析器

21、BeanFactory 和 FactoryBean?:BeanFactory是Spring的bean容器,FactoryBean是工厂bean,可以来生成Bean的一种Bean

14、Spring Bean的作用域:
  Singleton:Spring IOC容器中只有一个共享的Bean实例,一般都是Singleton作用域。
  Prototype:每一个请求,会产生一个新的Bean实例。
  Request:每一次http请求会产生一个新的Bean实例。

36、 如果⼀个接⼝有2个不同的实现, 那么怎么来Autowire⼀个指定的实现?:Qualifier | @Autowire是byType,@Resource是ByName-->ByType

37、 Spring的声明式事务 @Transaction注解⼀般写在什么位置? 抛出了异常会⾃动回滚吗?有没有办法控制不触发回滚? | 一般在接口实现的方法上,会自动回滚,在注解上配置属性noRollbackFor

38、 如果想在某个Bean⽣成并装配完毕后执⾏⾃⼰的逻辑,可以什么⽅式实现?:Intialization接口afterProperties方法

39、SpringBoot没有放到web容器⾥为什么能跑HTTP服务?:自带嵌入式tomcat

43、怎样拦截SpringMVC的异常,然后做⾃定义的处理,⽐如打⽇志或者包装成JSON

45、struts2和springMVC的区别

46、spring框架中需要引用哪些jar包,以及这些jar包的用途:spring-core,spring-bean,spring-context 

50、spring注入的几种方式:@Setter,@Constructor,@Autowire,@Resource

90、Spring 的 IOC 和 AOP 有了解吗?
  IOC:控制反转,(解耦合)将对象间的依赖关系交给 Spring 容器,使用配置文件来创建所依赖的对象,由主动创建对象改为了被动方式;
  AOP:面向切面编程,将功能代码从业务逻辑代码中分离出来。

91、AOP 的实现方式有哪几种?如何选择?(必考)

答:JDK 动态代理实现和 cglib 实现。有接口定义则可以使用jdk,没有则用cglib。

   spring对aop的实现原理:ProxyFactoryBean | AbstractAutoProxyCreator | AspectJ语法 | XML方式

 

1、BeanFactory 和 ApplicationContext 有什么区别:Application支持父子容器,支持web。。。

2、Spring Bean 的生命周期:

3、Spring IOC 如何实现:扫描源码解析出BeanDefination,管理BeanDefination的依赖,反射生成Bean实例,根据BeanDefination的依赖注入bean

5、Spring AOP 实现原理:动态代理,拦截器

6、动态代理(cglib 与 JDK):有接口定义则可以使用jdk,没有则用cglib。

8、Spring 事务底层原理:底层是AOP实现的

12、Spring 的单例实现原理:采用Map实现的单例

13、Spring 框架中用到了哪些设计模式:工厂模式,观察者模式,动态代理。。。

17、SpringMVC运行原理
  1.客户端请求提交到DispatcherServlet
  2.由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。
  3.Controller调用业务逻辑处理后,返回ModelAndView
  4.DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
  5.视图负责将结果显示到客户端

24、Spring Bean 的生命周期,如何被管理的?

25、Spring Bean 的加载过程是怎样的?

26、如果要你实现Spring AOP,请问怎么实现?

27、如果要你实现Spring IOC,你会注意哪些问题?:对象依赖管理,继承,反射

28、Spring 是如何管理事务的,事务管理机制?

29、Spring 的不同事务传播行为有哪些,干什么用的?

    PROPAGATION_REQUIRED:外部没有事务,就新开一个事务

    PROPAGATION_SUPPORTS:外部有事务,就用这个事物,没有就算了

    PROPAGATION_MANDATORY:外部没有事物,就不干(异常)

    PROPAGATION_REQUIRES_NEW:不管外部有没有事务,都新开独立的一个事务

    PROPAGATION_NOT_SUPPORTED:不管外部有没有事物,都不使用事务

    PROPAGATION_NEVER:外部有事务,就不干(异常)

    PROPAGATION_NESTED:外部有事务,就新开一个子事务,savepoint

32、Spring 循环注入的原理?:

33、Spring AOP的理解,各个术语,他们是怎么相互工作的?:Advice,PointCut,Advisor

34、Spring 如何保证 Controller 并发的安全?:Spring针对Controller可以配置scope,用来制定是request,session,prototype,还是singleton

51. spring如何实现事物管理的:基于AOP实现的

52. springIOC和AOP的原理

55. springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的
  核心:控制反转和面向切面
  请求处理流程:
    1。首先用户发送请求到前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;
    2。页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名);
    3。前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;
    4。前端控制器再次收回控制权,将响应返回给用户。
  控制反转如何实现:
    我们每次使用spring框架都要配置xml文件,这个xml配置了bean的id和class。
    spring中默认的bean为单实例模式,通过bean的class引用反射机制可以创建这个实例。
    因此,spring框架通过反射替我们创建好了实例并且替我们维护他们。
    A需要引用B类,spring框架就会通过xml把B实例的引用传给了A的成员变量。

59、spring循环依赖及解决办法:http://blog.csdn.net/caomiao2006/article/details/46511123
60、springmvc工作流程和原理:http://blog.csdn.net/liangzi_lucky/article/details/52459378
61、spring注解原理:http://blog.csdn.net/u010987379/article/details/52152795

62、Spring AOP 实现原理?
  参考 :http://blog.csdn.net/moreevan/article/details/11977115/

63、@transactional注解在什么情况下会失效,为什么?:调用同一个类的方法的时候,spring容器通过aop提供为bean提供事务管理功能,方法内部调用是调用的对象本身的方法,不是调用的spring容器的bean

64、SpringMVC的Controller是如何将参数和前端传来的数据一一对应的。
65、Quartz是如何完成定时任务的。
68、Spring的IOC有什么优势。
69、Spring如何维护它拥有的bean。:BeanDefination集合来管理。。

72、Springmvc与Struts区别#
  参考文章:
  http://blog.csdn.net/tch918/article/details/38305395
  http://blog.csdn.net/chenleixing/article/details/44570681

76、Springbean的加载过程(推荐看Spring的源码)#
参考文章http://geeekr.com/read-spring-source-1-how-to-load-bean/

77、Springbean的实例化(推荐看Spring的源码)#
参考文章http://geeekr.com/read-spring-source-two-beans-initialization/

78、Spring如何实现AOP和IOC(推荐看Spring的源码)#
参考文章http://www.360doc.com/content/15/0116/21/12385684_441408260.shtml

79、Springbean注入方式#
参考文章http://blessht.iteye.com/blog/1162131

80、Spring的事务管理#
这个主题的参考文章没找到特别好的,http://blog.csdn.net/trigl/article/details/50968079这个还可以。

81、Spring事务的传播特性#
参考文章http://blog.csdn.net/lfsf802/article/details/9417095

80、springmvc原理
参考文章http://blog.sina.com.cn/s/blog_7ef0a3fb0101po57.html

82、Spring 事务的隔离性,并说说每个隔离性的区别

解答:Spring事务详解

85、Struts跟Spring mvc的优缺点,让你选会如何选

解答:Spring MVC 与 Struts的区别

86、简单说说Spring 事务机制

解答:Spring事务机制

89、Spring的原理

答:Spring的核心是IOC和AOP  ,IOC是依赖注入和控制反转, 其注入方式可分为set注入、构造器注入、接口注入等等。IOC就是一个容器,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。简单理解就是:JAVA每个业务逻辑处理至少需要两个或者以上的对象协作进行工作,但是每个对象在使用它的合作对象的时候,都需要频繁的new 对象来实现,你就会发现,对象间的耦合度高了。而IOC的思想是:Spring容器来管理这些,对象只需要处理本身业务关系就好了。至于什么是控制反转,就是获得依赖对象的方式反转了。
AOP呢,面向切面编程,最直接的体现就是Spring事物管理。至于Spring事物的相关资料,就不细说了,参考:Spring注解式事物管理

 90、JDK 动态代理如何实现?(加分点)

答:JDK 动态代理,只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。

  1. 定义一个实现接口 InvocationHandler 的类;
  2. 通过构造函数,注入被代理类;
  3. 实现 invoke( Object proxy, Method method, Object[] args)方法;
  4. 在主函数中获得被代理类的类加载器;
  5. 使用 Proxy.newProxyInstance( ) 产生一个代理对象;
  6. 通过代理对象调用各种方法。

92、Spring MVC 的核心控制器是什么?消息处理流程有哪些?

答:核心控制器为 DispatcherServlet。消息流程如下:

 

 

15、代理的共有优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。
  Java静态代理:
    代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。
    缺点:一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。
  Java动态代理:
    Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法可以进行增强处理的逻辑的编写,这个公共代理类在运行的时候才能明确自己要代理的对象,同时可以实现该被代理类的方法的实现,然后在实现类方法的时候可以进行增强处理。
  实际上:代理对象的方法 = 增强处理 + 被代理对象的方法
 

16、JDK和CGLIB生成动态代理类的区别:
  JDK动态代理只能针对实现了接口的类生成代理(实例化一个类)。此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑
  CGLIB是针对类实现代理,主要是对指定的类生成一个子类(没有实例化一个类),覆盖其中的方法 。

 

17、Spring AOP应用场景
  性能检测,访问控制,日志管理,事务等。

87、Spring 4.0新特性

解答:Spring4新特性

 

 

 

 

Netty

1、为什么选择 Netty:因为netty是nio实现的,高并发的情况下比mina表现要好

2、说说业务中,Netty 的使用场景:通信组件,rpc通信组件,mq通信组件

3、原生的 NIO 在 JDK 1.7 版本存在 epoll bug:空转,如果不到超时时间唤醒了,则记录1次,超过512次则重新创建SelectionKey重新注册所有事件

4、什么是TCP 粘包/拆包:链路层对数据进行拆分数据包和合并数据包

5、TCP粘包/拆包的解决办法:业务曾手动拆分数据包

7、说说 Netty 的零拷贝:内核态,不用在用户态之间切换

14、了解哪几种序列化协议?包括使用场景和如何去选择

16、Netty的高性能表现在哪些方面:nio

18.NIO的组成?:Channel(通道),Selector(选择器),ByteBuffer(各种缓冲器)

26.NIOEventLoopGroup源码?

6、Netty 线程模型:Reactor模型

8、Netty 内部执行流程:

9、Netty 重连实现:在final里重现连接

11、Netty 的各大组件:

  Channel、EventLoop和ChannelFuture

  ChannelHandler和ChannelPipeline

  Bootstrapping

12、Netty的线程模型:BossGroup,WorkerGroup

13、TCP 粘包/拆包的原因及解决方法

 

 

Mybatis

1、Mybatis流程
  每一个Mybatis的应用程序都以一个SqlSessionFactory对象的实例为核心。首先用字节流通过Resource将配置文件读入,然后通过SqlSessionFactoryBuilder().build方法创建SqlSessionFactory,然后再通过SqlSessionFactory.openSession()方法创建一个SqlSession为每一个数据库事务服务。
  经历了Mybatis初始化 –>创建SqlSession –>运行SQL语句,返回结果三个过程

3、mybatis如何处理结果集
  MyBatis的结果集是通过反射来实现的。并不是通过get/set方法。在实体类中无论是否定义get/set()方法,都是可以接收到的。

5、mybatis分页及分页插件原理:http://blog.csdn.net/jaryle/article/details/52315565

6、mybatis插件原理:http://blog.csdn.net/hupanfeng/article/details/9247379
7、mybatis动态sql原理:http://www.importnew.com/24160.html
8、mybatis延迟加载:http://blog.csdn.net/eson_15/article/details/51668523

9、Mybatis如何找到指定的Mapper的,如何完成查询的。

 

Dubbo

1.什么是rcp框架:https://www.cnblogs.com/ChrisMurphy/p/6550184.html
2.序列化方式方式及作用:http://blog.csdn.net/u012554102/article/details/51902697
3.dubbo底层协议实现:https://www.cnblogs.com/1201x/p/6482638.html
4.dubbo注册中心如何设置:http://blog.csdn.net/u011659172/article/details/51491518
5.dubbo负载均衡的理解:https://www.cnblogs.com/qingfengbuluo/p/5527930.html
6.dubbo容错机制:https://www.2cto.com/kf/201612/572681.html
7.服务调用超时的实现原理:https://www.cnblogs.com/ASPNET2008/p/7292472.html
8.服务注册与发现的流程:http://doc.okbase.net/661116/archive/241946.html

17、Dubbo的底层实现原理和机制

22、Dubbo的服务请求失败怎么处理:

  集群容错策略

  failover:失败则尝试访问其他provider

  failfast:失败立马返回

  failsafe:失败直接忽略

  failback:失败定时重发

  forking:并行调用多个provider,只要有一个返回则返回

  broadcast:所有provider都调一遍

41、dubbo的组件有哪些,各有什么作用。

  dubbo-rpc:提供rpc以及序列化功能

  dubbo-registry:提供服务注册订阅相关功能

  dubbo-remoting:提供rpc访问通信功能

43、dubbo是如何利用接口就可以通信的。:动态代理,封装了rpc,序列化,通信等复杂性

5、说说 Dubbo 的实现原理:

  服务提供方暴露自己的服务,并注册到zk上,服务消费者在zk上订阅服务

  消费者订阅到服务后,将客户端访问参数组装成一个消息对象,加密传输到服务提供方,服务提供方解密参数并调用本地方法,将返回结果加密返回,客户端再解密返回结果

 

 

 

 

微服务篇

微服务

1、前后端分离是如何做的:m站,前后端同学统一制定好接口定义,APP前端同学页面展示效果,后端提供业务接口功能,并通过mtop平台暴露给前端团队使用

2、微服务哪些框架:eurke

3、你怎么理解 RPC 框架:业务提供者暴露服务,并提供一个访问地址,客户端通过访问地址访问暴露的服务,涉及到数据传输和数据序列化 | 序列化、反序列化,IO传输,服务注册和订阅,服务路由

4、说说 RPC 的实现原理:客户端调用 => 消息对象 => 数据加密 => 网络传输 => 服务端数据解密成消息对象 => 服务端调用服务 => 返回结果数据加密 => 网络传输回写 => 客户端解密成返回结果

  参考:https://liuzhengyang.github.io/2016/12/16/rpc-principle/

6、你怎么理解 RESTful

7、说说如何设计一个良好的 API

  可读性:一眼就能看出接口含义

  。。。

8、如何理解 RESTful API 的幂等性

   同一个请求访问多次系统的影响与访问一次相同,比如查询

9、如何保证接口的幂等性

  查询,删除,唯一索引校验,token机制防止重复提交,访问带seq做唯一索引

10、说说 CAP 定理、 BASE 理论

11、怎么考虑数据一致性问题

  由于分布式环境下,CAP只能满足俩,所以可以采用弱一致性的方案来解决一致性问题,比如弹外添加观演人,采用谈外异步更新到弹内,保证了分区容忍性和有效性,弱一致性方案

12、说说最终一致性的实现方案

  比如数据同步,或者分库分表数据汇总到一个库

13、你怎么看待微服务

  

14、微服务与 SOA 的区别

  

15、如何拆分服务

  按照业务拆分,高内聚低耦合

16、微服务如何进行数据库管理

  

17、如何应对微服务的链式调用异常:调用链路跟踪,全链路日志

18、对于快速追踪与定位问题

19、微服务的安全

 

 

 

分布式---------------zk,dubbo,消息中间件|分布式session,分布式锁,分布式事务,负载均衡,分库分表,分布式ID

1、谈谈业务中使用分布式的场景

  业务层分布出去形成分布式服务,消息队列分布出去形成分布式消息队列,数据访问分布出去形成分布式数据存储。。。 

11、zookeeper是什么;

   分布式协调服务,常用在分布式系统中,屏蔽分布式系统访问底层的复杂配置

12、zookeeper哪里用到;

  分布式服务的服务注册+订阅

13、zookeeper的选主过程;:zab协议

14、zookeeper集群之间如何通讯;

  zab协议  

15、你们的zookeeper的节点加密是用的什么方式;

26、Zookeeper的用途,选举的原理是什么?

  分布式协调服务,屏蔽分布式访问的复杂细节

28、zookeeper原理和适用场景

29、zookeeper watch机制

30、redis/zk节点宕机如何处理

36、zookeeper的选举策略

42、zookeeper的负载均衡算法有哪些。?zk有负载均衡?zk在集群负载均衡中的协调

    

18、描述一个服务从发布到被消费的详细过程

  provider暴露服务,注册服务到zk--》consumer订阅在zk上订阅服务

19、分布式系统怎么做服务治理

  

20、接口的幂等性的概念

 

33、用过哪些MQ,怎么用的,和其他mq比较有什么优缺点,MQ的连接是线程安全的吗

  ActiveMq,MetaQ,

34、MQ系统的数据如何保证不丢失

  消息刷盘,消息消费确认

46、消息队列的原理和实现

47、Redis实现消息队列

  答:Redis实现消息队列     、参考2

 

  

2、Session 分布式方案:session复制,session粘连,session共享

9、分布式Session框架
  配置服务器,Zookeeper集群管理服务器可以统一管理所有服务器的配置文件
  共享这些Session存储在一个分布式缓存中,可以随时写入和读取,而且性能要很好,如Memcache,Tair。
  封装一个类继承自HttpSession,将Session存入到这个类中然后再存入分布式缓存中
  由于Cookie不能跨域访问,要实现Session同步,要同步SessionID写到不同域名下。

40、分布式session如何设计。

44、集群环境中,session如何实现共享

  1.Java集群之session共享    

       2、session多服务器共享方案,还有一种方案就是使用一个固定的服务器专门保持session,其他服务器共享

 

 

3、分布式锁的场景:弹内选座生成静态页,抽奖专题扣减名额和库存

4、分布是锁的实现方案:zookeeper(临时节点),redis(setnx)

16、分布式锁的实现过程;:setnx成功则视为获取锁成功,释放锁的时候删除key

39、分布式锁如何设计。

  redis中获取锁时,需要给锁设置一个缓存过期时间,防止当前节点获取到锁后挂了,导致分布式锁无法释放
       释放锁时,需要确保获取到锁的情况下,才能去删除锁节点

5、分布式事务:TCC,1pc,2pc,3pc,txc

24、对分布式事务的理解:保证分布式系统之间的数据一致性问题

38、分布式事务的控制。

 

6、集群与负载均衡的算法与实现:dubbo负载均衡算法(roundrobin,random,leastactive,conisistenHash)

25、如何实现负载均衡,有哪些算法可以实现?

23、重连机制会不会造成错误:有可能,比如接口超时重连,需要保证接口幂等性,否则对数据有影响

 

 

7、说说分库与分表设计

8、分库与分表带来的分布式困境与应对之策

27、数据的垂直拆分水平拆分。:垂直拆分为按照业务来拆分,水平拆分是把数据量很多的表拆分成很多个小表,加快读写速度,提高性能

35、列举出你能想到的数据库分库分表策略;分库分表后,如何解决全表查询的问题

   策略:按照id取模分表,按照字符串hash分表

   将分库分表的数据同步汇总到一个全量库,在全量库上全表查询

31、分布式集群下如何做到唯一序列号

  数据库单条记录+ID批量生成服务

37、全局ID

 

45、分布式、集群环境中,缓存如何刷新,如何保持同步?

  A、缓存如何刷新? 1、定时刷新  2、主动刷新覆盖   ,每个缓存框架都有自带的刷新机制,或者说缓存失效机制,就拿Redis和 Ehcache举例, 他们都有自带的过期机制,另外主动刷新覆盖时,只需获取对应的key进行数据的覆盖即可

  B、缓存如何保持同步?  这个redis有自带的集群同步机制,即复制功能,具体参考:基于Redis分布式缓存实现      ,Ehcache也有分布式缓存同步的配置,只需要配置不同服务器地址即可,参照:Ehcache分布式缓存同步

48、谈谈你对分布式的理解

  个人理解:分布式就是把一个系统/业务 拆分成多个子系统/子业务 去协同处理,这个过程就叫分布式,具体的演变方式参考:Java分布式应用技术架构介绍

 

 

 

 

安全与性能篇

性能优化

1、性能指标有哪些

2、如何发现性能瓶颈

3、性能调优的常见手段

4、说说你在项目中如何进行性能调优

5、web如何项目优化

  解答:web项目性能优化(整理)

6、日常项目中,如果你接手,你准备从哪些方面调优?

  答:这个呢首先是了解哪些需要优化,需要优化肯定是项目性能遭遇瓶颈或者猜测即将遭遇了,我们才会去考虑优化。那么怎么优化?

  a、扩容 ,扩容的理解,就是扩充服务器并行处理的能力,简单来说就是加服务器,增加处理请求的能力,例如增加nginx 、tomcat等应用服务器的个数,或者物理服务器的个数,还有加大服务器带宽等等,这里考虑的是硬件方面

  b、调优 ,调优,包括系统调优和代码调优 。 系统调优就是说加快处理速度,比如我们所提到的CDN、ehcache、redis等缓存技术,消息队列等等,加快服务间的响应速度,增加系统吞吐量,避免并发,至于代码调优,这些就需要多积累了,比如重构、工厂等, 数据库调优的话这个我不是很懂,只知道索引和存储过程,具体参考:Mysql数据库调优21个最佳实践  ,其他数据库调优方面就各位自己找找吧

 

 

 

 

 

工程篇

需求分析

1、你如何对需求原型进行理解和拆分

2、说说你对功能性需求的理解

3、说说你对非功能性需求的理解

4、你针对产品提出哪些交互和改进意见

5、你如何理解用户痛点

设计能力

1、说说你在项目中使用过的 UML 图

2、你如何考虑组件化

3、你如何考虑服务化

4、你如何进行领域建模

5、你如何划分领域边界

6、说说你项目中的领域建模

7、说说概要设计

设计模式

1、你项目中有使用哪些设计模式

2、说说常用开源框架中设计模式使用分析

3、说说你对设计原则的理解

4、23种设计模式的设计理念

5、设计模式之间的异同,例如策略模式与状态模式的区别

6、设计模式之间的结合,例如策略模式+简单工厂模式的实践

7、设计模式的性能,例如单例模式哪种性能更好。

业务工程

1、你系统中的前后端分离是如何做的

2、说说你的开发流程

3、你和团队是如何沟通的

4、你如何进行代码评审

5、说说你对技术与业务的理解

6、说说你在项目中经常遇到的 Exception

7、说说你在项目中遇到感觉最难Bug,怎么解决的

8、说说你在项目中遇到印象最深困难,怎么解决的

9、你觉得你们项目还有哪些不足的地方

10、你是否遇到过 CPU 100% ,如何排查与解决

11、你是否遇到过 内存 OOM ,如何排查与解决

12、说说你对敏捷开发的实践

13、说说你对开发运维的实践

14、介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色

15、重构过代码没有?说说经验;

 

场景

16、一千万的用户实时排名如何实现;:zset的score特性(ZINCRBY修改score) 

17、五万人并发抢票怎么实现;:反向代理,页面静态化+cdn,限流 | 动静分离,冷热分离,集群+负载均衡,缓存,缓存预热 | 读写分离,分库分表,连接池

18、大型网站应用之海量数据解决方案 
        http://blog.csdn.net/zhaojw_420/article/details/70881230

19、大型网站应用之高并发情况下的解决方案 
        http://blog.csdn.net/zhaojw_420/article/details/70881266

20、在一个千万级的数据库查寻中,如何提高查询效率? :

  分库分表,读写分离,建立索引

  或者

  建立索引,避免全表扫描 | 避免not in, !=之类,因为全表扫描|union all 替换 or,避免全表扫描(不同索引字段or)| like没有满足最左原则也会全表扫描|where中使用参数,等号左边使用表达式,函数也会全表扫描

  避免使用*返回无用的字段| exisits代替in

        http://blog.csdn.net/zhaojw_420/article/details/69367682

21、用wait-notify 写一段代码来解决生产者-消费者问题,更进一步,在分布式的环境下怎么解决

  wait()和notify()都是线程间通信的方法,可以直接对线程的行为进行操作。他们的本质其实是传递生产者-消费者各自的消息,理解了这一点,那么在分布式环境下就很简单了,只要找到一个第三方的可以用来传递消息的媒介(Zookeeper、Redis、Kafka等)就可以了。

  

 1 Object[] list = new Object[10];
 2 
 3 public void produce(){
 4         sychronized(list){
 5             while(true){
 6                if(list.size() >= 10){
 7                    list.wait();//等待消费者消费
 8                 }
 9              //work
10               list.add(new Object());
11               list.notify();//通知消费者
12             }
13         }   
14 }
15 
16 public void consume(){
17         sychronized(list){
18              while(true){
19                  if(list.size() <= 0){
20                       list.wait();//等待生产者生产
21                  }
22                 //work          
23                 list.remove(0);
24                 list.notify();//通知生产者
25              }   
26         }
27 }

 

  

22.、设计一个线程池

  A:可以参考Java线程池的理论与实践

  如果对JDK的线程池java.util.concurrent.ThreadPoolExecutor比较了解,可以把一些简单的特性放上去。如果不了解,可以直接设计一个线程数组,然后加一些业务逻辑。所谓线程池,基本也就如此。

23、 设计一个IOC容器
  A:用反射,注解,还有IOC的理论
25、手机扫二维码登录是怎么实现的?
  参考:http://www.jianshu.com/p/7f072ac61763
26、如何保证RESTful API安全性 ?

  对客户端做身份验证:参数加签,oauth协议

  对敏感数据加密,防止篡改:https

  身份认证之后的授权

  参考: http://blog.csdn.net/ywk253100/article/details/25654101

27、项目并发如何处理?(我们是web项目)

  解答:高并发量网站解决方案,另外,还有数据库乐观锁,数据库读写分离、使用消息队列、多用存储过程等等

29、平台上的图片如何防盗链:refer字段

  解答:http下载防盗链原理:http协议的字段referer记录来实现

30、如何区分上传的图片是不是木马?

  解答:1、看上传的图片后缀  2、如何后缀是篡改的,那么每个文件有个魔术数字  文件上传-魔术数字

31、你的接口服务数据被人截包了,你如何防止数据恶意提交?

  答:我们可以在接口传输参数里面设置一个业务编号,这个编号用来区分是否重复提交。这样即使数据被抓包了,对方也无法区分每个字段你的含义,这时,这个业务编号的作用就来了

32、假设服务器经常宕机,你从哪些方面去排查问题?

  答:先重启,并开启jvm输出gc日志||看是不是系统问题,如果不是则看是不是jvm问题,在看是不是oom,sof等

33、下单3min还未支付,发短信提醒

  有两种,一种是采用定时任务扫库,时间不一定准确 | 一种是zset,score设置为当前时间+3min,扫描zset发现时间到了,如果该订单未支付,则发送短信

 

 

 

 

 

 

 

 

 

 

posted on 2018-05-28 12:39  Vindia  阅读(298)  评论(0)    收藏  举报

导航