Java并发:重入锁 ReentrantLock

ReentrantLock 是一种可重入的互斥锁,它不像 synchronized关键字一样支持隐式的重进入,但能够使一个线程(不同的方法)重复对资源的重复加锁而不受阻塞。

ReentrantLock 的 Java类图:

其中抽象静态内部类 Sync 继承了 AQS,可见 ReentrantLock 是通过组合自定义同步器来实现锁的获取与释放。

ReentrantLock 的构造函数能控制锁的公平性表现:

1     public ReentrantLock(boolean fair) {
2         sync = fair ? new FairSync() : new NonfairSync();
3     }

公平锁的够减少“饥饿”发生概率,等待越久的请求越能够优先的到满足。

公平性与否是针对获取锁而言的,一个锁若是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,先到先得。

公平性锁每次都是从同步队列中的第一个节点获取到锁,而非公平性锁会出现一个线程连续获取锁的情况,特别是刚释放锁的线程在次获取同步状态的几率会更大,使得其他线程在同步队列中等待。

在系统线程上下文切换方面上,非公平性锁的切换次数会明显少于公平性锁,因为公平性锁的切换开销相对更大,但是极少的线程切换能保证更大吞吐量。

ReentrantLock 类代码的基本结构:

 1 public class ReentrantLock implements Lock, java.io.Serializable {
 2     private final Sync sync;
 3 
 4     //默认无参构造函数,默认为非公平锁
 5     public ReentrantLock() {
 6         sync = new NonfairSync();
 7     }
 8 
 9     //带参数的构造函数,决定是公平锁还是非公平锁
10     public ReentrantLock(boolean fair) {
11         sync = fair ? new FairSync() : new NonfairSync();
12     }
13 
14     //抽象基类继承AQS,公平锁与非公平锁继承该类,并分别实现其lock()方法
15     abstract static class Sync extends AbstractQueuedSynchronizer {
16         abstract void lock();
17         //省略..
18     }
19     
20     //非公平锁实现
21     static final class NonfairSync extends Sync {...}
22     
23     //公平锁实现
24     static final class FairSync extends Sync {....}
25    
26     //锁实现,根据具体子类实现调用
27     public void lock() {
28         sync.lock();
29     }
30 
31     //响应中断的获取锁
32     public void lockInterruptibly() throws InterruptedException {
33         sync.acquireInterruptibly(1);
34     }
35 
36     //尝试获取锁,默认采用非公平锁方法实现
37     public boolean tryLock() {
38         return sync.nonfairTryAcquire(1);
39     }
40 
41     //超时获取锁
42     public boolean tryLock(long timeout, TimeUnit unit)
43             throws InterruptedException {
44         return sync.tryAcquireNanos(1, unit.toNanos(timeout));
45     }
46 
47     //释放锁
48     public void unlock() {
49         sync.release(1);
50     }
51 
52     //创建锁条件(从Condetion来理解,就是创建等待队列)
53     public Condition newCondition() {
54         return sync.newCondition();
55     }
56 
57     //省略....
58 }

ReentrantLock 释放锁的方法,在抽象静态内部类 Sync 中,它会检查当前线程同步状态值(重复获取一次锁,状态值会增加),在释放同步状态时减少同步状态值,若该锁获取了 n 次,那么前(n-1)次返回的都是 false,只有同步状态完全释放了(c为0),才会把占有该资源的线程设置为空,并返回 true。

 1     protected final boolean tryRelease(int releases) {
 2             int c = getState() - releases;
 3             if (Thread.currentThread() != getExclusiveOwnerThread())
 4                 throw new IllegalMonitorStateException();
 5             boolean free = false;
 6             if (c == 0) {
 7                 free = true;
 8                 setExclusiveOwnerThread(null);
 9             }
10             setState(c);
11             return free;
12         }
原文地址:https://www.cnblogs.com/magic-sea/p/11586548.html