ReentrantLock(可重入锁)和synchronized区别

  • 可重入性:ReentrantLock字面意思即为再进入锁,称为可重入锁,其实synchronize所使用的锁也是可以重入的,两者关于这个区别不打,它们都是同一个线程进入一次,锁的计数器进行自增,要等到锁的计数器下降为零时,才能释放锁

  • 锁的实现:synchronized依赖于JVM实现无法了解底层源码,而ReentrantLock基于JDK实现通过阅读源码了解实现,区别就类似于操作系统控制实现与用户使用代码实现。

  • 性能区别:在synchronized优化以前,性能比ReentrantLock差很多,但自从synchronize引入了偏向锁、轻量级锁(自选锁)后 ,也就是自循锁后,两者性能差不多(JDK1.6以后,为了减少获得锁和释放锁所带来的性能消耗,提高性能,引入了“轻量级锁”和“偏向锁”)。在两种场景下都可以使用,官方更推荐使用synchronized,因为写法更容易。synchronized的优化其实是借鉴了ReentrantLock中的CAS技术,都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

  • 功能区别:

    • 便利性:synchronized更便利,它是由编译器保证加锁与释放。ReentrantLock是需要手动声明与释放锁,所以为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
    • 锁的细粒度和灵活度:ReentrantLock优于synchronized
  • ReentrantLock独有的功能

    • ReentrantLock可以指定是公平锁还是非公平锁,synchronized只能是非公平锁。(所谓公平锁就是先等待的线程先获得锁)
    • 提供了一个Condition类,可以分组唤醒需要唤醒的线程。不像是synchronized要么随机唤醒一个线程,要么全部唤醒。
    • 提供能够中断等待锁的线程的机制,通过lock.lockInterruptibly()实现,这种机制ReentrantLock是一种自选锁,通过循环调用CAS操作来实现加锁。性能比较好的原因是避免了进入内核态的阻塞状态。想进办法避免线程进入内核阻塞状态, 是我们分析和理解锁设计的关键

  如果满足ReentrantLock三个独有的功能,那么必须使用ReentrantLock。其他情况下可以根据性能、业务场景等等来选择synchronized还是ReentrantLock

是否要放弃synchronized

  synchronized能做的,ReentrantLock都能做;而ReentrantLock能做的,而synchronized却不一定做得了。性能方面,ReentrantLock不比synchronized差,那么要放弃使用synchronized

  1. J.U.C包中的锁定类是用于高级情况和高级用户的工具,除非说你对Lock的高级特性有特别清楚的了解以及有明确的需要,或这有明确的证据表明同步已经成为可伸缩性的瓶颈的时候,否则我们还是继续使用synchronized
  2. 相比较这些高级的锁定类,synchronized还是有一些优势的,比如synchronized不可能忘记释放锁。 在退出synchronized块时,JVM会自动释放锁,会很容易忘记要使用finally释放锁,这对程序非常有害。
  3. 还有当JVM使用synchronized管理锁定请求和释放时,JVM在生成线程转储时能够包括锁定信息,这些信息对调试非常有价值,它们可以标识死锁以及其他异常行为的来源。 而Lock类知识普通的类,JVM不知道哪个线程具有Lock对象,而且几乎每个开发人员都是比较熟悉synchronized


 

你可能感兴趣的:(java)