CountDownLatch和CyclicBarrier的主要区别:
1.CountDownLatch是1个线程等待另外多个线程,主线程要等待,其他线程可以继续做其他事情。
CyclicBarrier是多个线程互相等待,都不能做其他事情。
2.CountDownLatch不能重置,用一次就丢弃。
CyclicBarrier可以通过reset重置。
CyclicBarrier源码解析
CyclicBarrier是通过显示锁ReentrantLock来锁存对象
核心方法await()
barrier的步骤。n-1个线程进去await方法后,都在for(;;)等待。
直到最后一个线程进入await后,将其他所有线程唤醒。
CountDownLatch使用了AbstractQueuedSynchronizer作为辅助类,这是一个适用于所有使用int值作为state状态量的同步辅助类。
并且重写了
值得一提的是,如果不重写这2个方法,或抛出UnsupportedOperationException();因为在父类中如下定义
跟abstract方法相比,这个非强制的,并且捕获的是一个RuntimeException
第一个核心方法countDown()主要是在上面那个方法中
这段调用了一个Unsafe的本地CAS方法(CompareAndSet)
使计数器state减1.
第二个核心方法await()是在AbstractQueuedSynchronizer类中doAcquireSharedInterruptibly(int arg)
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;
}
}
}
}