Java面试那点事——基础200115
1. 什么是锁消除?什么是锁膨胀
锁消除:
对数据进行逃逸分析。对象实例都是存在于线程共享的堆中的,即便是局部变量的对象,也是存在于堆中,但是局部变量对象的引用是存在于方法栈中的,方法栈是线程私有,线程之间彼此不可见,当对于这样的引用进行加锁和释放锁的时候,其实是没有必要的,因为数据是不会逃逸出去,比如说StringBuffer的append方法,是synchronized修饰的同步方法,虚拟机检测到这类情况不会发生数据逃逸就会在运行的时候消除锁,从而提高性能。
锁膨胀/锁粗化:
原则上需要尽量缩小加锁的范围,把需要同步的代码的范围尽量缩小,这样其他线程可以尽快的获得锁。
但是如果频繁对同一个对象进行加锁和解锁的操作,频繁的同步互斥操作会造成不必要的性能损耗;对于这种情况,需要把加锁提前到对象的第一个操作之前,解锁释放到最后一个对象,例子:StringBuffer对象变成全部局部,此时变成堆的线程共享。
2. 乐观锁有哪几种?主要思想是什么?
乐观锁:偏向锁、轻量级锁、自旋锁
乐观锁的主要思想是:CAS(compare and swap)
CAS是一种思想,并不是一种锁,它是一种原子操作,通过比较传入的值来判断是否更新,一样则更新,不一样则失败。
3. 多线程锁的升级原理是什么?
锁的级别从低到高:
无锁—偏向锁—轻量级锁—重量级锁
无锁:不加锁,所有线程都可以对资源进行访问,失败则重试
偏向锁:适用于必须同步但是只有一个线程执行的代码块,虚拟机检测到同步的代码块只有一个线程持续执行,就会在后续加上偏向锁。减少非竞争条件的同步代码,提升性能。
轻量级锁:只有一个线程执行同步代码块的时候会加上偏向锁,当第二个线程加入竞争,偏向锁就会升级会轻量级锁,第二个线程不会阻塞,而是通过自旋等待第一个线程释放锁。第二个线程自旋(也就是CPU空转)可以避免用户态和内核态的转换,提升性能。
重量级锁:当第三个线程加入竞争,轻量级锁就会升级为重量级锁,线程会阻塞等待,直到线程释放锁。
4. 什么是死锁?如何预防死锁?死锁和活锁的区别是什么?
死锁:多个线程因竞争资源而造成的互相等待,没有外力作用则一直等待下去。
死锁条件:
- 互斥
- 不剥夺
- 请求和保持
- 循环等待
活锁:死锁和活锁的表现都是程序不在运行,但是死锁中所有线程都是出于阻塞状态的,活锁中所有线程都是活的状态,是在运行,不断的try,但是不在继续执行,在做无用功。
【Java 面试那点事】
这里致力于分享 Java 面试路上的各种知识,无论是技术还是经验,你需要的这里都有!
这里可以让你【快速了解 Java 相关知识】,并且【短时间在面试方面有跨越式提升】
面试路上,你不孤单!