Java并发编程的艺术,学习笔记(三)CountDownLatch CyclicBarrier

工具类

  • CountDownLatch
    • CountDownLatch 内部简单介绍
      • 初始化
  • CyclicBarrier

CountDownLatch

先看一段实例代码:

public static void main(String[] args) {
	// 初始化 3个计数
    CountDownLatch countDownLatch = new CountDownLatch(3);
    new Thread(()->{
        countDownLatch.countDown();// 第一次计数-1
        System.out.println("123");
        countDownLatch.countDown();// 第二次-1
        System.out.println("124");
        System.out.println(System.currentTimeMillis());
    }).start();
    new Thread(()->{
        try {
            Thread.sleep(3000);// 睡3s
            countDownLatch.countDown();// 计数再-1
            System.out.println("thread2 "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
    try {
        countDownLatch.await();// 主线程等待计数为0
        System.out.println("mThread " + System.currentTimeMillis());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果就是:

123
124
1547367298416
thread2 1547367301421
mThread 1547367301421

当线程2,睡3s后,计数-1 等于0,表示结束了,线程也结束了所以回到了主线程。
await() 方法 返回,打印时间。
这个类就像 join()方法,等待其他当线程结束,但CountDownLatch 提供了比join()方法更实在的一个功能就是await(long timeout, TimeUnit unit)。带超时的功能。

CountDownLatch 内部简单介绍

Java并发编程的艺术,学习笔记(三)CountDownLatch CyclicBarrier_第1张图片
可以看到 CountDownLatch内部有个Sync类他是实现自AbstractQueuedSynchronizer(AQS)队列同步器,在上一篇已经有比较详细的介绍了,AQS的功能。

初始化

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    // 初始化 队列同步器
    this.sync = new Sync(count);
}

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;
    Sync(int count) {
    	// 设置state值,这里就像重入锁一样一共重入了几次或者是被共享了几次。
        setState(count);
    }
    int getCount() {
        return getState();
    }
    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))
                return nextc == 0;
        }
    }
}

CountDownLatch 的初始化 就是类似设值,这可直接猜测到 他的countdown 肯定是释放锁的过程,state-1

public void countDown() {
    sync.releaseShared(1);
}

CyclicBarrier

cyclic(循环)barrier (屏障),作用是:让一组线程到达这个屏障时被阻塞,最后一个线程到达的时候屏障被打开,所有被拦截的线程继续运行。

public static void main(String[] args) {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
    new Thread(()->{
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println("123");
    }).start();
    new Thread(()->{
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println("321");
    }).start();
    System.out.println("1111");
}
输出结果:
1111
321
123

上面的结果不够直观,如果只要去掉一个await(), 就会进入无限等待的状态。
当然也存在,超时的await() 方法。

private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException,
           TimeoutException {
    final ReentrantLock lock = this.lock;
    // 首先需要获取锁
    lock.lock();
    try {
        final Generation g = generation;
        if (g.broken)
            throw new BrokenBarrierException();
        if (Thread.interrupted()) {
        	// 如果线程被中断,则直接打破屏障
            breakBarrier();
            throw new InterruptedException();
        }
        // 这里是关键,每次碰到个await,初始化的时候的count就会--,直到0
        int index = --count;
        if (index == 0) {  // tripped
            boolean ranAction = false;
            try {
            	// 如果初始化有赋值过,命令,就是所有线程到的时候就会马上执行的runable
                final Runnable command = barrierCommand;
                if (command != null)
                    command.run();
                ranAction = true;
                // 方法里面会打破 barrier
                nextGeneration();
                return 0;
            } finally {
            	// 这里大概是怕command run 的时候会遇到异常,如果上面没有打破,最终还是会进行一次打破,如果然 Action是false的话
                if (!ranAction)
                    breakBarrier();
            }
        }
        // loop until tripped, broken, interrupted, or timed out
        for (;;) {
            try {
            	// 如果还不是最后一个线程,则会进入等待队列
                if (!timed)
                    trip.await();
                else if (nanos > 0L)
                    nanos = trip.awaitNanos(nanos);
            } catch (InterruptedException ie) {
                if (g == generation && ! g.broken) {
                    breakBarrier();
                    throw ie;
                } else {
                    // We're about to finish waiting even if we had not
                    // been interrupted, so this interrupt is deemed to
                    // "belong" to subsequent execution.
                    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();
    }
}

你可能感兴趣的:(thread)