十一、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 完结或中断线程。