synchronized 和 ReentrantLock 的区别

239 阅读3分钟

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

一、概述

synchronizedReentrantLock 这是两个同步锁,有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的。

这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。很明显,Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。但是锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized的。

在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

二、两者的共同点:

  1. 都是用来协调多线程对共享对象、变量的访问;
  2. 都是可重入锁,同一线程可以多次获得同一个锁;
  3. 都保证了可见性和互斥性。

三、两者的不同点:

  1. ReentrantLock 显示的获得、释放锁,synchronized 隐式获得释放锁;
  2. ReentrantLock 可响应中断、可轮回,synchronized 是不可以响应中断的,为处理锁的 不可用性提供了更高的灵活性;
  3. ReentrantLock 是 API 级别的,synchronized 是 JVM 级别的;
  4. ReentrantLock 可以实现公平锁;
  5. ReentrantLock 通过 Condition 可以绑定多个条件;
  6. 底层实现不一样, synchronized 是同步阻塞,使用的是悲观并发策略,lock 是同步非阻 塞,采用的是乐观并发策略;
  7. Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言 实现;
  8. synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生; 而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象, 因此使用 Lock 时需要在 finally 块中释放锁;
  9. Lock 可以让等待锁的线程响应中断,而 synchronized 却不行,使用 synchronized 时, 等待的线程会一直等待下去,不能够响应中断;
  10. 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到;
  11. Lock 可以提高多个线程进行读操作的效率,既就是实现读写锁等。