Board logo

标题: Java并发编程-再谈 AbstractQueuedSynchronizer 1 :独占模式(1) [打印本页]

作者: look_w    时间: 2019-1-17 19:36     标题: Java并发编程-再谈 AbstractQueuedSynchronizer 1 :独占模式(1)

独占模式acquire实现流程有了上面的这些基础,我们看一下独占式acquire的实现流程,主要是在线程acquire失败后,是如何构建数据结构的,先看理论,之后再用一个例子画图说明。
看一下AbstractQuueuedSynchronizer的acquire方法实现流程,acquire方法是用于独占模式下进行操作的:
1
2
3
4
5
public final void acquire(int arg) {
      if (!tryAcquire(arg) &&
          acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
          selfInterrupt();
}



tryAcquire方法前面说过了,是子类实现的一个方法,如果tryAcquire返回的是true(成功),即表明当前线程获得了一个执行当前动作的资格,自然也就不需要构建数据结构进行阻塞等待。
如果tryAcquire方法返回的是false,那么当前线程没有获得执行当前动作的资格,接着执行”acquireQueued(addWaiter(Node.EXCLUSIVE), arg))”这句代码,这句话很明显,它是由两步构成的:
分别看一下每一步做了什么。
addWaiter先看第一步,addWaiter做了什么,从传入的参数Node.EXCLUSIVE我们知道这是独占模式的:
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;
}



首先看第4行~第11行的代码,获得当前数据结构中的尾节点,如果有尾节点,那么先获取这个节点认为它是前驱节点prev,然后:
因此在数据结构中有节点的情况下,所有新增节点都是作为尾节点插入数据结构。从注释上来看,这段逻辑的存在的意义是以最短路径O(1)的效果完成快速入队,以最大化减小开销。
假如当前节点没有被设置为尾节点,那么执行enq方法:
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;
            }
        }
    }
}



这段代码的逻辑为:
看完了代码,用一张图表示一下AbstractQueuedSynchronizer的整体数据结构(比较简单,就不自己画了,网上随便找了一张图):





欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0