File tree Expand file tree Collapse file tree 1 file changed +66
-1
lines changed Expand file tree Collapse file tree 1 file changed +66
-1
lines changed Original file line number Diff line number Diff line change 4
4
5
5
而 ` ReentrantLock ` 就是一个普通的类,它是基于 ` AQS(AbstractQueuedSynchronizer) ` 来实现的。
6
6
7
+ 它是一个** 重入锁** ,一个线程获得了锁之后仍然可以** 反复** 的加锁,不会出现自己阻塞自己的情况。
8
+
7
9
> ` AQS ` 是 ` Java ` 并发包里实现锁、同步的一个基础框架。
8
10
9
11
@@ -90,4 +92,67 @@ ReentrantLock 分为**公平锁**和**非公平锁**,可以通过构造方法
90
92
return false ;
91
93
}
92
94
}
93
- ```
95
+ ```
96
+
97
+ 首先会判断 ` AQS ` 中的 ` state ` 是否等于0,0 就表示当前没有其他线程获得锁,当前线程就可以尝试获取锁。
98
+
99
+ 注意:尝试之前会利用 ` hasQueuedPredecessors() ` 方法来判断 AQS 的队列中中是否有其他线程,如果有则就不会尝试获取锁了(** 这是公平锁特有的情况** )。
100
+
101
+ 如果队列中没有线程就利用 CAS 来将 AQS 中的 state 修改为1,也就是获取锁,获取成功则将当前线程置为获得锁的独占线程(` setExclusiveOwnerThread(current) ` )。
102
+
103
+ 如果 ` state ` 大于 0 时,说明锁已经被获取了,则需要判断获取锁的线程是否为当前线程(` ReentrantLock ` 支持重入),是则需要将 ` state + 1 ` ,并将值更新。
104
+
105
+
106
+ #### 写入队列
107
+ 如果 ` tryAcquire(arg) ` 获取锁失败,则需要用 ` acquireQueued(addWaiter(Node.EXCLUSIVE), arg) ` 将当前线程写入队列中。
108
+
109
+ 写入之前需要将当前线程包装为一个 ` Node ` 对象(` addWaiter(Node.EXCLUSIVE) ` )。
110
+
111
+ > AQS 中的队列是由 Node 节点组成的双向链表实现的。
112
+
113
+
114
+ 包装代码:
115
+
116
+ ``` java
117
+ private Node addWaiter(Node mode) {
118
+ Node node = new Node (Thread . currentThread(), mode);
119
+ // Try the fast path of enq; backup to full enq on failure
120
+ Node pred = tail;
121
+ if (pred != null ) {
122
+ node. prev = pred;
123
+ if (compareAndSetTail(pred, node)) {
124
+ pred. next = node;
125
+ return node;
126
+ }
127
+ }
128
+ enq(node);
129
+ return node;
130
+ }
131
+
132
+ ```
133
+
134
+ 首先判断队列是否为空,不为空时则将封装好的 ` Node ` 利用 ` CAS ` 写入队尾,如果出现并发写入失败就需要调用 ` enq(node); ` 来写入了。
135
+
136
+ ``` java
137
+ private Node enq(final Node node) {
138
+ for (;;) {
139
+ Node t = tail;
140
+ if (t == null ) { // Must initialize
141
+ if (compareAndSetHead(new Node ()))
142
+ tail = head;
143
+ } else {
144
+ node. prev = t;
145
+ if (compareAndSetTail(t, node)) {
146
+ t. next = node;
147
+ return t;
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ 这个处理逻辑就相当于自旋加上 ` CAS ` 保证一定写入队列。
155
+
156
+
157
+
158
+
You can’t perform that action at this time.
0 commit comments