Java并发编程(10) —— ReentrantLock类详解

一、ReentrantLock介绍

ReentrantLock是juc.locks包中的一个独占式可重入锁,相比synchronized,它可以创建多个条件等待队列,还支持公平/非公平锁、可中断、超时、轮询等特性。

ReentrantLock实现Lock接口实现了一个锁所需的方法,如lock()、unLock()等,在这些方法中实际上是调用继承了AQS的同步器Sync对象中的方法来实现对锁资源的获取与释放,而内部类Sync有两个子类FairSync和NonfairSync,分别对应公平锁和非公平锁。ReentrantLock默认构造器是构造公平锁
Java并发编程(10) —— ReentrantLock类详解_第1张图片
Java并发编程(10) —— ReentrantLock类详解_第2张图片
在这里插入图片描述

二、ReentrantLock特性详解

1. 多条件队列

Sync对象中开放了创建AQS中条件队列ConditionObject对象的方法,并重写了isHeldExclusively()方法(通知方法signal()要用到),因此可创建条件队列实现通知等待机制。
Java并发编程(10) —— ReentrantLock类详解_第3张图片

2. 非公平 & 公平锁

非公平锁NonfairSync

  • 新进来的线程会先直接与同步队列中的线程竞争CAS
  • 竞争失败则调用acquire -> tryAcquire -> nonfairTryAcquire继续竞争,再失败才会在acquire方法中后续执行加入同步队列
  • 若线程是重入这个锁,会记录重入次数,若超过int范围溢出则抛出错误
    Java并发编程(10) —— ReentrantLock类详解_第4张图片
    Java并发编程(10) —— ReentrantLock类详解_第5张图片

公平锁FairSync

  • 新来的线程若同步队列为空才竞争锁,否则tryAcquire直接返回false然后进入队列排队,实现先来后到公平锁
  • 同样也会记录重入次数
    Java并发编程(10) —— ReentrantLock类详解_第6张图片

3. 可中断

我们知道synchronized在锁竞争时是不可中断的,获取不到锁的线程会一直处于阻塞状态。而ReentrantLock调用lockInterruptibly()获取锁的过程是可以响应中断的,其内部调用的是AQS的acquireInterruptibly()方法,当收到中断信号时会退出阻塞然后抛出InterruptedException异常从而退出锁竞争。

4. 超时

调用tryLock(long timeout, TimeUnit unit)获取锁可实现超时功能,当超过时间还未获取到锁则直接抛出异常退出锁竞争
Java并发编程(10) —— ReentrantLock类详解_第7张图片

内部是AQS中调用LockSupport.parkNanos()超时阻塞实现的

5. 轮询

ReentrantLock的轮询特性是指可通过tryLock()方法尝试获取锁,没获取到则不阻塞直接退出,可以过会再来尝试。tryLock()调用Sync中定义的nonfairTryAcquire方法,从前面列出的源码可知没获取到则直接返回false
在这里插入图片描述

三、ReentrantLock类和synchronized关键字的区别

ReentrantLock和synchronized都是独占式可重入锁,但是它们有如下区别:

  1. 锁实现机制:ReentrantLock是一个类,是基于AQS实现的,依赖于JDK的API;synchronized是一个关键字,是直接在JVM层面通过监视器实现的锁机制。
  2. 条件等待队列:ReentrantLock通过Condition可创建多个条件等待队列;而synchronized依赖的监视器模型中只有一个等待队列。
  3. 非公平 & 公平锁:ReentrantLock支持公平和非公平锁;synchronized为非公平锁
  4. 其他特性:ReentrantLock还支持可中断、超时、轮询等特性;synchronized不支持这些

一般来说在不需要用到ReentrantLock特殊特性的时候就用synchronized,因为synchronized显然相对来说使用起来更加简洁高效

参考:https://blog.csdn.net/zhengzhaoyang122/article/details/110847701

你可能感兴趣的:(#,Java并发编程,java,开发语言)