1、synchronized关键字可以实现什么类型的锁?
- 悲观锁:synchronized关键字实现的是悲观锁,每次访问共享资源时都会上锁。
- 非公平锁:synchronized关键字实现的是非公平锁,即线程获取锁的顺序并不一定是按照线程阻塞的顺序。谁先抢占,谁执行。
- 可重入锁:synchronized关键字实现的是可重入锁,即已经获取锁的线程可以再次获取锁。
- 独占锁或者排他锁:synchronized关键字实现的是独占锁,即该锁只能被一个线程所持有,其他线程均被阻塞。
2、JDK1.6为什么要对synchronized进行优化?
因为Java虚拟机是通过进入和退出Monitor对象来实现代码块同步和方法同步的,而Monitor是依靠底层操作系统的Mutex Lock来实现的,操作系统实现线程之间的切换需要从用户态转换到内核态,这个切换成本比较高,对性能影响较大。
3、JDK1.6对synchronized做了哪些优化?
在JDK1.6中,为了减少获得锁和释放锁带来的性能消耗,引入了偏向锁和轻量级锁,锁的状态变成了四种。锁的等级从 无锁->偏向锁->轻量级锁->重量级锁 逐步升级,并且是单向的,不会出现锁的降级。
4、偏向锁的原理(或偏向锁的获取流程)、偏向锁的好处是什么(获取偏向锁的目的是什么)?
引入偏向锁的目的:减少只有一个线程执行同步代码块时的性能消耗。获取流程:
- 检查对象头中Mark Word是否为可偏向状态,如果不是则直接升级为轻量级锁。
- 如果是,判断Mark Work中的线程ID是否指向当前线程,如果是,则执行同步代码块。
- 如果不是,则进行CAS自旋竞争锁,如果竞争到锁,则将Mark Work中的线程ID设为当前线程ID,执行同步代码块。
- 如果竞争失败,升级为轻量级锁。
5、了解锁消除吗?
锁消除是指Java虚拟机在即时编译时,通过对运行上下的扫描,消除那些不可能存在共享资源竞争的锁。锁消除可以节约无意义的请求锁时间。
6、了解锁粗化吗?
如果一系列连续的操作一直对某个对象反复加锁和解锁,频繁地进行互斥同步操作也会引起不必要的性能消耗。将多个连续加锁、解锁的操作连接在一起,扩展成为一个范围更大的锁。
7、synchronized和volatile的区别?
- volatile主要是保证内存的 可见性,即变量在寄存器中的内存是不确定的,需要从主存中读取。synchronized主要是解决多个线程访问资源的同步性。
- volatile 作用于变量,synchronized作用于代码块或者方法。
- volatile 仅可以保证数据的可见性,不能保证数据的原子性。synchronized可以保证数据的可见性和原子性。
- volatile 不会造成线程的阻塞,synchronized会造成线程的阻塞。
8、synchronized和Lock的区别?
- synchronized是Java语法的一个关键字,加锁的过程是在JVM底层进行。Lock是一个类,是JDK应用层面的,在JUC包里有丰富的API。
- synchronized在加锁和解锁操作上都是自动完成的,Lock锁需要我们手动加锁和解锁。
- Lock可以判断锁的状态,synchronized不可以判断锁的状态。
- synchronized能修饰方法和代码块,Lock锁只能锁住代码块。
- synchronized是非公平锁,而Lock锁既有非公平锁也有公平锁,可以由开发者通过参数控制。
- Lock锁有丰富的API,可根据不同的场景,在使用上更加灵活。
锁竞争不是很激烈的场景,使用synchronized,语义清晰,实现简单,JDK1.6后引入了偏向锁,轻量级锁等概念后,性能也能保证。而在锁竞争激烈,复杂的场景下,则使用Lock锁会更灵活一点,性能也较稳定。