循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置『计数个数』,每个线程执行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行
功能和 countdownlatch 一样, 但是 CyclicBarrier 可以循环使用
private static void test01() { ExecutorService service = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { CountDownLatch latch = new CountDownLatch(2); service.submit(() -> { log.debug("start ... "); latch.countDown(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } log.debug("end ... "); }); service.submit(() -> { log.debug("start ... "); latch.countDown(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } log.debug("end ... "); }); service.submit(() -> { log.debug("sum start ... "); try { latch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } log.debug("sum end ... "); }); } service.shutdown(); }
可以看到上面的代码我们在每次循环的时候 , 都需要创建 CountDownLatch latch = new CountDownLatch(2);
CountDownLatch
允许一个或者多个线程去等待其他线程完成操作。
CountDownLatch
接收一个int
型参数,表示要等待的工作线程的个数。
也不一定是多线程,在单线程中可以用这个int型参数表示多个操作步骤。
CountDownLatch 用来进行线程同步协作,等待所有线程完成倒计时。
其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一
ReentrantLock
,Semaphore
,其他的诸如ReentrantReadWriteLock
,SynchronousQueue
,FutureTask
等等皆是基于AQS的。当然,我们自己也能利用AQS非常轻松容易地构造出符合我们自己需求的同步器。AQS核心思想是:
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。