Java并发源码之ReentrantLock(一)

版权声明:本文为博主原创文章,转载请注明出处,谢谢!

版权声明:本文为博主原创文章,转载请注明出处:http://blog.jerkybible.com/2017/09/29/Java并发源码之ReentrantLock-一/

访问原文「Java并发源码之ReentrantLock(一)

ReentrantLock介绍

ReentrantLock是一个可重入的互斥锁,与使用synchronized方法和语句访问的隐式监视锁具有相同的基本行为和语义,但具有扩展功能。ReentrantLock属于最后一个成功加锁并且还没有释放锁的线程。当一个线程请求lock时,如果锁不属于任何线程,将立马得到这个锁;如果锁已经被当前线程拥有,当前线程会立即返回。

下面这个图是与ReentrantLock相关的UML类图,可以看到ReentrantLock实现了LockSerializable接口,表示它实现了lock()unlock()Lock的接口方法,并且是一个可以序列化的类。ReentrantLock主要成员变量为SyncSync是一个抽象类,继承了AbstractQueuedSynchronizer(简称AQS),AQS提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架,本文不详细介绍。而Sync有两个实现类:NonfairSyncFairSync,分别代表非公平锁和公平锁。也就是说ReentrantLock中所有的锁操作都是由sync这个成员变量完成的。

ReentrantLock构造方法

下面的代码为它的构造函数,可以看到无参构造函数直接返回非公平锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 创建一个ReentrantLock实例
* 等同于调用ReentrantLock(false).
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 根据公平策略创建一个ReentrantLock实例
*
* @param fair 如果采用公平锁则为true
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

ReentrantLock加锁方法

下面是三个常用的ReentrantLock加锁方法,分别为locktryLocklockInterruptibly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* 获得锁.
*
* 如果锁没有被另一个线程保持并且立即返回,则将锁定计数设置为1
*
* 如果当前线程已经保持锁定,则保持计数增加1,该方法立即返回
*
* 如果锁被另一个线程保持,则为了进行线程调度将当前线程禁用,
* 并且在锁定被获取之前处于休眠状态,此时锁定保持计数被设置为1
*/
public void lock() {
sync.lock();
}
/**
* 只有在调用时它不被另一个线程占用才能获取锁
*
* 如果没有被另一个线程占用,则获取锁定,并立即返回true,将锁定保持计数设置为1
*
* 即使此锁已设置为使用合理的排序策略,如果锁可用,则调用tryLock将立即获取锁定,
* 无论其他线程是否正在等待锁
*
* 这种行为尽管打破了公平,但是在某些情况下是有用的。如果要遵守此锁的公平性设置,
* 请使用几乎相等的tryLock(long,TimeUnit)
*
* 如果当前线程已经保存该锁,则保持计数增加1,该方法返回true
* 如果锁由另一个线程保存,则该方法将立即返回值为false
*
* @return 如果锁是空闲的并且被当前线程获取,或者锁已经被当前线程占据,返回true;
* 否则返回false
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
* 获取锁定,除非当前的线程被中断
*
* 如果锁没有被另一个线程保持并且立即返回,则将锁定计数设置为1
*
* 如果当前线程已经保存此锁,则保持计数增加1,该方法立即返回
*
* 如果锁被另一个线程保持,则当前线程将被禁用以进行线程调度,并且休眠,
* 直到发生两件事情之一:
* 1. 当前线程获取锁
* 2. 一些其他线程中断当前线程
*
* 如果当前线程获取锁定,则锁定保持计数设置为1。
*
* 如果当前的线程:
* 1. 在进入此方法时设置了中断状态
* 2. 在获取锁时中断
* 则抛出InterruptedException并清除当前线程的中断状态
*
* 在该实现中,由于该方法是明确的中断点,所以优先考虑响应中断超过正常或可重入的锁定
*
* @throws InterruptedException 如果当前线程中断
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

上面代码的注释已经很明白,这里我总结一下:

  1. lock:拿不到lock就不会结束,不然线程就一直等待
  2. tryLock:马上返回,拿到lock返回true,否则返回false
  3. lockInterruptibly:线程在请求lock并被阻塞时,如果被中断,则此线程会被唤醒并被要求处理InterruptedException。并且如果线程已经被interrupt,再使用lockInterruptibly的时候,此线程也会被要求处理interruptedException

ReentrantLock释放锁方法

ReentrantLock的释放锁方法比较简单,只有一个unlock。下面是它的说明。

1
2
3
4
5
6
7
8
9
10
11
/**
* 尝试释放此锁
*
* 如果当前线程是该锁的持有者,则保持计数递减。 如果保持计数现在为零,则锁定被释放。
* 如果当前线程不是此锁的持有者,则会抛出IllegalMonitorStateException
*
* @throws IllegalMonitorStateException 如果当前线程不是此锁的持有者
*/
public void unlock() {
sync.release(1);
}

ReentrantLock其他方法

下面列出了ReentrantLock的其他方法都比较好理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* 返回一个与此Lock实例一起使用的Condition实例.
*
* Condition将Object监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,
* 以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待 set(wait-set)。
* 其中,Lock替代了synchronized方法和语句的使用,
* Condition替代了Object监视器方法的使用。
*
*
* @return Condition实例
*/
public Condition newCondition() {
return sync.newCondition();
}
/**
* 查询当前线程对此锁的持有数量.
*
* 一个线程对于与无解锁每个锁定动作都持有一个锁定
*
* @return 当前线程对此锁定的保持数,如果此锁定不被当前线程占用,则为零
*/
public int getHoldCount() {
return sync.getHoldCount();
}
/**
* 查询此锁是否由当前线程持有.
*
* @return 如果当前线程持有此锁,则为true,否则为false
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* 查询此锁是否由任何线程持有。 该方法设计用于监视系统状态,不用于同步控制.
*
* @return 如果当前线程持有此锁,则为true,否则为false
*/
public boolean isLocked() {
return sync.isLocked();
}
/**
* 如果此锁的公平设置为true,则返回true。
*
* @return 如果此锁的公平设置为true,则返回true。
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 返回当前拥有该锁的线程,如果不拥有则返回null
*
* @return 返回当前拥有该锁的线程,如果不拥有则返回null
*/
protected Thread getOwner() {
return sync.getOwner();
}
/**
* 查询是否有线程正在等待获取此锁
*
* @return 如果可能有其他线程等待获取锁则返回true
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 查询给定的线程是否等待获取此锁
*
* @param thread 给定的线程
* @return 给定的线程如果等待获取此锁则返回true
* @throws NullPointerException 给定的线程为null
*/
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* 返回等待获取此锁的线程数的估计
*
* @return 返回等待获取此锁的线程数的估计
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 返回一个包含可能正在等待获取此锁的线程的集合
*
* @return 包含线程的集合
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 查询是否有任何线程正在等待与此锁相关联的给定condition
*
* @param condition Condition实例
* @return 如果有任何等待线程,则为true
* @throws IllegalMonitorStateException 如果没有持有锁
* @throws IllegalArgumentException condition没有与锁相关联
* @throws NullPointerException condition为null
*/
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters(
(AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回与此锁相关联的给定condition等待的线程数的估计
*
* @param condition Condition实例
* @return 估计数量
* @throws IllegalMonitorStateException 如果没有持有锁
* @throws IllegalArgumentException condition没有与锁相关联
* @throws NullPointerException condition为null
*/
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength(
(AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回包含可能在与此锁相关联的给定condition下等待的线程的集合
*
* @param condition Condition实例
* @return 线程集合
* @throws IllegalMonitorStateException 如果没有持有锁
* @throws IllegalArgumentException condition没有与锁相关联
* @throws NullPointerException condition为null
*/
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads(
(AbstractQueuedSynchronizer.ConditionObject)condition);
}

总结一下

本文仅仅是对ReentrantLock做了简单的介绍,包括主要结构和主要方法。通过上面的描述可以看到,ReentrantLock所有的方法都交给了它的sync成员变量来完成。接下来将会对公平锁和非公平锁进行分析。

Jerky Lu wechat
欢迎加入微信公众号