ReentrantLock和synchronized的区别

145 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

首先,synchronized没有优化之前,是重量级锁,性能非常差,而且它的功能单一,wait和notify只有一个条件,功能非常单一,就是在这种需求下,在JDK5的时候引入了ReentrantLock。它弥补了当时synchronized性能差的缺点,而且相较于ReentrantLock,它的功能更多,更加灵活,具体来讲有以下几点:

1、从锁的获取来看,用synchronized一旦获取锁之后,其他线程需要等待,假设获取锁的线程阻塞了,其他线程依然得等待,容易造成死锁。ReentrantLock通过trylock尝试获取锁,成功则继续,否则就立刻返回,而不用阻塞,也可以设置等待时间,极大地减少了发生死锁的可能。

2、从锁的释放来看,synchronized是线程执行完同步后就释放锁,或者线程执行异常了释放锁,而ReentrantLock在finally必须释放锁,不然容易造成线程死锁、

3、从锁的类型上看,synchronized是可重入锁,但不可中断且是非公平的锁;而ReentrantLock也是可重入锁,但可以设置为公平锁或者非公平锁,在构造方法中直接写fair或者unfair即可,并且ReentrantLock可以通过lockInterruptibly()响应中断

4、性能方面,在synchronized优化之前,ReentrantLock的性能远高于synchronized,但是synchronized优化以后他们的性能差异已经不大,所以在一般场景下,甚至某些源码中,用的都是synchronized,比如双亲委派的代码

5、从功能上来看,ReentrantLock通过条件变量condition关联多个条件,实现生产者消费者模型,而synchronized不行,wait和notify只能有一个条件。所以在多个条件变量和高度竞争锁的地方,ReentrantLock更加适合

6、实现原理不同,synchronized是Java关键字,在JVM层面实现的,也就是阻塞的线程是由JVM调度器来进行唤醒的。而ReentrantLock需要通过lock和unlock显式锁来实现锁的获取和释放。Synchronized实现的原理是在它修饰的地方,经过编译之后会生成两条字节码指令,指令指定一个引用类型来尝试获取对象的锁,锁的互斥量存放在对象头之中。而ReentrantLock内部使用AQS队列同步器来实现,使用一个int类型的成员变量来表示同步状态,使用CAS来获取锁。

同:

1、都是可重入锁

2、都是通过加锁实现的同步

总的来说,Synchronized使用起来更加方便,而ReentrantLock功能更多,1.8之后对Synchronized进行了锁优化,其实他们性能差不多了,在实际使用过程中大部分情况推荐使用Synchronized