CountDownLatch和CyclicBarrier源码解析

CountDownLatch和CyclicBarrier的主要区别:

1.CountDownLatch是1个线程等待另外多个线程,主线程要等待,其他线程可以继续做其他事情。

CyclicBarrier是多个线程互相等待,都不能做其他事情。

2.CountDownLatch不能重置,用一次就丢弃。

CyclicBarrier可以通过reset重置。


CyclicBarrier源码解析

CyclicBarrier是通过显示锁ReentrantLock来锁存对象



/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();


核心方法await()

private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException,
TimeoutException {
    final ReentrantLock lock = this.lock;
lock.lock();
    try {
        final Generation g = generation;//主要用于判断barrier是否被破坏

        if (g.broken)
            throw new BrokenBarrierException();

        if (Thread.interrupted()) {
            breakBarrier();
            throw new InterruptedException();
}

       int index = --count;//每有一个线程通过,index就会自减。
       if (index == 0) {  // tripper跳出等待。
boolean ranAction = false;
           try {
               final Runnable command = barrierCommand;
               if (command != null)//如果barrier构造的时候,附带一个Runnable,可以用于计时器
                   command.run();
ranAction = true;
nextGeneration();//其他所有线程的唤醒在这里。!
               return 0;
} finally {
               if (!ranAction)
                   breakBarrier();
}
       }

        //循环等待,直到跳出,中断,或者barrier被破坏。
for (;;) {
            try {
                if (!timed)
                    trip.await();//lock显示锁里的await方法。
                else if (nanos > 0L)//如果设置了等待时间。
                    nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
                if (g == generation && ! g.broken) {
                    breakBarrier();
                    throw ie;
} else {
                    // 一个弥补的解决方法,确保线程完全中断。
Thread.currentThread().interrupt();
}
            }

            if (g.broken)
                throw new BrokenBarrierException();

            if (g != generation)
                return index;

            if (timed && nanos 0L) {
                breakBarrier();
                throw new TimeoutException();
}
        }
    } finally {
        lock.unlock();
}
}


barrier的步骤。n-1个线程进去await方法后,都在for(;;)等待。
直到最后一个线程进入await后,将其他所有线程唤醒。

CountDownLatch使用了AbstractQueuedSynchronizer作为辅助类,这是一个适用于所有使用int值作为state状态量的同步辅助类。

并且重写了
protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;//使计数器减一
                if (compareAndSetState(c, nextc))//本地CAS方法,刷新state的值
                    return nextc == 0;
            }
        }

值得一提的是,如果不重写这2个方法,或抛出UnsupportedOperationException();因为在父类中如下定义
protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }

跟abstract方法相比,这个非强制的,并且捕获的是一个RuntimeException

第一个核心方法countDown()主要是在上面那个方法中
if (compareAndSetState(c, nextc))
                    return nextc == 0;

这段调用了一个Unsafe的本地CAS方法(CompareAndSet)
使计数器state减1.


第二个核心方法await()是在AbstractQueuedSynchronizer类中doAcquireSharedInterruptibly(int arg)

private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);//把主线程添加到等待队列,下面有详细讲解
        boolean failed = true;
        try {
            for (;;) {//循环等待,阻塞主线程。
                final Node p = node.predecessor();//获得节点node的前继
                if (p == head) {//确保前继是头节点。
                    int r = tryAcquireShared(arg);//判断计数器,如果计数器state=0
那么会返回1;
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);//唤醒主线程
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);//一个构造方法,把主线程添加到等待队列,后继是一个共享节点
        // 尝试直接把node节点设置为尾节点,
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);//主要是初始化头节点,并且把node设置为尾节点。
        return node;
    }

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)) {//尾节点设置为node
                    t.next = node;//设置node为头节点的后继。注意此时t指向的是head.
                    return t;
                }
            }
        }
    }

猜你喜欢

转载自251195187.iteye.com/blog/2206937