Java并发编程-再谈 AbstractQueuedSynchronizer 1 :独占模式(4)
- UID
- 1066743
|
Java并发编程-再谈 AbstractQueuedSynchronizer 1 :独占模式(4)
实战举例:数据结构构建上面的例子讲解地过于理论,下面利用ReentrantLock举个例子,但是这里不讲ReentrantLock实现原理,只是利用ReentrantLock研究AbstractQueuedSynchronizer的acquire和release。示例代码为:
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
| /**
* @author 五月的仓颉http://www.cnblogs.com/xrq730/p/7056614.html
*/
public class AbstractQueuedSynchronizerTest {
@Test
public void testAbstractQueuedSynchronizer() {
Lock lock = new ReentrantLock();
Runnable runnable0 = new ReentrantLockThread(lock);
Thread thread0 = new Thread(runnable0);
thread0.setName("线程0");
Runnable runnable1 = new ReentrantLockThread(lock);
Thread thread1 = new Thread(runnable1);
thread1.setName("线程1");
Runnable runnable2 = new ReentrantLockThread(lock);
Thread thread2 = new Thread(runnable2);
thread2.setName("线程2");
thread0.start();
thread1.start();
thread2.start();
for (;;);
}
private class ReentrantLockThread implements Runnable {
private Lock lock;
public ReentrantLockThread(Lock lock) {
this.lock = lock;
}
@Override
public void run() {
try {
lock.lock();
for (;;);
} finally {
lock.unlock();
}
}
}
}
|
全部是死循环,相当于第一条线程(线程0)acquire成功之后,后两条线程(线程1、线程2)阻塞,下面的代码就不考虑后两条线程谁先谁后的问题,就一条线程(线程1)流程执行到底、另一条线程(线程2)流程执行到底这么分析了。
这里再把addWaiter和enq两个方法源码贴一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node prev = tail;
if (prev != null) {
node.prev = prev;
if (compareAndSetTail(prev, node)) {
prev.next = node;
return node;
}
}
enq(node);
return node;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
|
首先第一个acquire失败的线程1,由于此时整个数据结构中么没有任何数据,因此addWaiter方法第4行中拿到的prev=tail为空,执行enq方法,首先第3行获取tail,第4行判断到tail是null,因此头结点new一个Node出来通过CAS算法设置为数据结构的head,tail同样也是这个Node,此时数据结构为:
为了方便描述,prev和next,我给每个Node随便加了一个地址。接着继续enq,因为enq内是一个死循环,所以继续第3行获取tail,new了一个空的Node之后tail就有了,执行else判断,通过第8行~第10行代码将当前线程对应的Node追加到数据结构尾部,那么当前构建的数据结构为:
这样,线程1对应的Node被加入数据结构,成为数据结构的tail,而数据结构的head是一个什么都没有的空Node。
接着线程2也acquire失败了,线程2既然acquire失败,那也要准备被加入数据结构中,继续先执行addWaiter方法,由于此时已经有了tail,因此不需要执行enq方法,可以直接将当前Node添加到数据结构尾部,那么当前构建的数据结构为:
至此,两个阻塞的线程构建的三个Node已经全部归位。 |
|
|
|
|
|