十一、HashMap和HashTable有什么区别?其底层实现是什么?

1、HashTable中每一个办法都加了锁,所以他是线程平安的,然而因为每个办法都加了锁,所以效率比拟低,目前用的比拟少。

2、HashMap容许Key和Value为null,而HashTable不容许。

3、底层实现:数组+链表

4、jdk8开始链表高度到8、数组长度超过64,链表转为红黑树。

5、如果产生hash抵触,先进行equals比拟,雷同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于64则将红黑树转为链表。

十二、ConcurrentHashMap原理,jdk7和jdk8版本的区别

ConcurrentHashMap和HashTable都是线程平安的,然而ConcurrentHashMap应用的是分段锁,所以效率比HashTable高。

1、jdk7:数据结构:ReentrantLock+Segment+HashEntry,一个Segment中蕴含一个HashEntry数组,每个HashEntry又是一个链表构造。

2、锁:Segment分段锁,Segment继承了ReentrantLock,锁定操作的Segment,其余的Segment不受影响,并发度为Segment个数,能够通过构造函数指定,数组扩容不会影响其余的segment

3、元素查问:二次hash,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。

4、get办法无需加锁,volatile保障

5、jdk8:数据结构:synchronized+CAS+Node+红黑树,Node的val和next都用volatile润饰,保障可见性,查找,替换,赋值操作都应用CAS

6、锁:锁链表的head节点,不影响其余元素的读写,锁力度更细,效率更高,扩容时,阻塞所有的读写操作、并发、扩容。

7、读操作无锁:Node的val和next应用volatile润饰,读写线程对该变量相互可见,数组用volatile润饰,保障扩容时被读线程感知。

十三、如何实现一个IOC容器

1、配置文件配置包扫描门路

2、递归包扫描获取.class文件

3、反射、确定须要交给IOC治理的类

4、对须要注入的类进行依赖注入

十四、什么是字节码?作用是什么

1、咱们平时写完的代码是.java后缀的,咱们通过编译成.class文件后就是字节码文件,字节码是java虚拟机可读的。

2、作用:java是将源码编译为.class文件,而后又通过虚拟机解释运行的,这样解决了传统解释性语言执行效率低的问题,同时又保障了解释型语言可移植的特点。

十五、Java类加载器有哪些

1、JDK自带有三个类加载器:bootstrap ClassLoader(疏导类加载器)、ExtClassLoader(扩大类加载器)、AppClassLoader(利用类加载器)。

2、bootstrap ClassLoader是EctClassLoader的父类加载器,默认加载lib下的jar包。

3、ExtClassLoader是AppClassLoader的父类加载器,负责加载lib/ext文件夹下的jar包。

4、AppClassLoader是利用类加载器,负责加载classpath下的类文件。

十六、双亲委派模型

十七、Java中的异样有哪些

1、Java中的所有异样都来自顶级父类Throwable。

2、Throwable下有两个子类Exception和Error。

3、Error是程序无奈解决的谬误,一旦呈现这个谬误,则程序将被迫进行运行。

4、Exception不会导致程序进行,又分为两种,一个是RunTimeExcepion运行时异样,另一个是CheckedException查看异样。

5、RunTimeException经常产生在程序运行过程中,会导致程序以后线程执行失败,CheckedException经常产生在程序编译过程中,会导致编译不通过。

十八、GC如何判断对象能够被回收

1、援用计数法:每个对象有一个援用计数属性,新增一个援用时计数加1,援用开释时计数减1,计数为0时能够回收。

2、可达性分析法:从GC Roots开始向下搜寻,搜寻所走过的门路成为援用链,当一个对象到GC Roots没有任何援用链相连时,则证实此对象时不可用的,那么虚拟机就判断是可回收对象。

3、GC Roots的对象有:

1》虚拟机栈中援用的对象(比方New User(),那么这个User就是GC Roots)

2》办法区中类动态属性援用的对象

3》办法区中常量援用的对象

4》本地办法栈中援用的对象

十九、线程的生命周期,线程有哪些状态

1、线程通常有五种状态,创立、就绪、运行、阻塞和死亡状态。

2、阻塞的状况又分为三种:

1》期待阻塞:运行的线程执行wait办法,该线程会开释占用的所有资源,JVM会把该线程放入“期待池”中,进入这个状态后,是不能主动唤醒的,必须依附其余线程调用notify或notifyAll办法能力被唤醒,wait是object类办法。

2》同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。

3》其余阻塞:运行的线程执行sleep或join办法,或者收回了I/O申请时,JVM会把该线程置为阻塞状态,当sleep状态超时、join期待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。sleep是Thread类的办法。

3、新建状态(New):新创建了一个线程对象。

4、就绪状态(Runnable):线程对象创立后,其余线程调用了该对象的start办法,该状态的线程位于可运行线程池中,变得可运行,期待获取cpu的使用权。

5、运行状态(Running):就绪状态的线程获取了cpu,执行程序代码。

6、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃cpu使用权,临时进行运行,直到线程进入就绪状态,才有机会转到运行状态。

7、死亡状态(Dead):线程执行完了或者因异样退出了run办法,该线程完结生命周期。

二十、sleep()、wait()、join()、yield()的区别

1、锁池

所有须要竞争同步锁的线程都会放在锁池当中,比方以后对象的锁曾经被其中一个线程失去,则其余线程须要在这个锁池进行期待,当后面的线程开释同步锁后锁池中的线程去竞争同步锁,当某个线程失去后会进入就绪队列进行期待CPU资源分配。

2、期待池

当咱们调用wait()办法后,线程会放到期待池当中,期待池的线程是不会去竞争同步锁,只用调用了notify()或notifyAll()后期待池的线程才会开始去竞争锁,notify()是随机从期待池选出一个线程放到锁池,而notifyAll()是将期待池的所有线程放到锁池当中。

3、sleep是Thread类的动态本地办法,wait则是Object类的本地办法。

4、sleep办法不会开释lock,然而wait会开释,而且会退出到期待队列中。

5、sleep办法不依赖于同步器synchronized,然而wait须要依赖synchronized关键字。

6、sleep个别用于以后线程休眠,或者轮询暂停操作,wait则多用于多线程之间的通信。

7、sleep会让出cpu执行工夫且强制上下文切换,而wait则不肯定,wait后可能还是有机会从新竞争到锁继续执行的。

8、yield()执行后线程间接进入就绪状态,马上开释了cpu的执行权,然而仍然保留了cpu的执行资格,所以有可能cpu下次进行线程调度还会让这个线程获取执行权继续执行。

9、join()执行后线程进入阻塞状态,例如在线程B中调用线程A的join(),那线程B会进入到阻塞队列,直到线程A完结或中断线程。