Lock和Synchronized的区别
Lock和Synchronized的区别
下面主要以可重入锁ReentrantLock为例。
两者相同点是:
- 都实现了多线程同步和内存可见性语义。
- 都是可重入锁。
两者不同点是:
- 同步实现机制不同,synchronized是通过Java对象头锁标记和Monitor对象实现同步;而ReentrantLock则是通过CAS、AQS和LockSupport(用于阻塞和解除阻塞)实现同步。
- 可见性实现机制不同,synchronized依赖JVM内存模型保证包含共享变量的多线程内存可见性;而ReentrantLock是通过AQS中的volatile state状态来保证包含共享变量的多线程内存可见性。
- 使用方式不同,synchronized 可以修饰实例方法(锁住实例对象)、静态方法(锁住类对象)、代码块(显示指定锁对象);ReentrantLock 显示调用 tryLock 和 lock 方法,需要在 finally 块中释放锁。
- 功能丰富程度不同,synchronized 不可设置等待时间、不可被中断(interrupted);ReentrantLock 提供有限时间等候锁(设置过期时间)、可中断锁(lockInterruptibly)、condition(提供 await、condition(提供 await、signal 等方法)等丰富功能。
- 锁类型不同,synchronized只支持非公平锁;而ReentrantLock提供公平锁和非公平锁实现,当然,在大部分情况下,非公平锁是高效的选择,但可能产生饥饿现象。
在 synchronized 优化以前,它的性能是比 ReenTrantLock 差很多的,但是自从 synchronized 引入了偏向锁,轻量级锁(自旋锁)等后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用 synchronized。
为什么非公平锁吞吐量大于公平锁?
公平锁最大的特点就是要排队等待唤醒,等待队列靠后的线程要等到靠前的都唤醒完才轮到,比如A、B、C在等待队列中,可能C在B被唤醒之前就可以执行完毕,非公平锁可以让C先执行,这样就省下了C等待和唤醒之间的性能消耗。非公平锁可以减少CPU的唤醒和阻塞次数。