JUC包下CountDownLatch学习笔记
CountDownLatch的作用是能使用多个线程进来之后,且线程任务执行完毕之后,才执行,
闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态。通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻断,一旦大门打开所有线程都将通过,但是一旦大门打开,所有线程都通过了,那么这个闭锁的状态就失效了,门的状态也就不能变了,只能是打开状态。也就是说闭锁的状态是一次性的,它确保在闭锁打开之前所有特定的活动都需要在闭锁打开之后才能完成。
与CountDownLatch第一次交互是主线程等待其它的线程,主线程必须在启动其它线程后立即调用await方法,这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
其他的N个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务,这种机制就是通过countDown()方法来完成的。每调用一次这个方法,在构造函数中初始化的count值就减1,所以当N个线程都调用了这个方法count的值等于0,然后主线程就能通过await方法,恢复自己的任务。
这里的主线程是相对的概念,需要根据CountDownLatch创建的场景分析。
package com.cxy.cyclicBarrier; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Created by Administrator on 2017/4/10. */ public class CountDownDemo { private static final Random random = new Random(); // 用于判断发令之前运是否已经进入准备状态,需要等待10个准备就绪,占有锁,等待10个完成,释放锁。 private static CountDownLatch readyLatch = new CountDownLatch(10); // 用于判断裁判是否已经发令,占有锁,等待裁判发令完成,释放锁 private static CountDownLatch startLatch = new CountDownLatch(1); public static void main(String[] args) { // 用于判断发令之前是否已经进入准备状态,需要等待10个准备就绪,占有锁,等待10个完成,释放锁。 // CountDownLatch readyLatch = new CountDownLatch(SPORTSMAN_COUNT); // 用于判断是否已经发令,占有锁,等待裁判发令完成,释放锁 // CountDownLatch startLatch = new CountDownLatch(1); // 启动10个线程,也就是10个,做准备工作 for (int i = 0; i < 10; i++) { Thread t = new Thread(new MyTask((i + 1) + "号", readyLatch, startLatch)); t.start(); } // 当前在其他准备就绪前一直等待,也就是说等readyLatch倒数计数器为0之前一直等待 try { readyLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 裁判发令,释放锁 startLatch.countDown(); System.out.println("老大:所有准备完毕,开始..."); } static class MyTask implements Runnable { private Lock lock = new ReentrantLock(); private CountDownLatch ready; private CountDownLatch start; private String name; public MyTask(String name, CountDownLatch ready, CountDownLatch start) { this.ready = ready; this.start = start; this.name = name; } @Override public void run() { lock.lock(); try { // 1. 准备就绪的逻辑,准备readyTime秒 int readyTime = random.nextInt(1000); System.out.println(name + ":我需要" + readyTime + "秒的时间准备。"); try { Thread.sleep(readyTime); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + "我已经准备完毕!"); // 释放锁readyLatch-1,表示一个已经就绪 ready.countDown(); try { // 等待发开始命令 start.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + ":行动..."); } catch (Exception e) { // TODO: handle exception } finally { lock.unlock(); } } } }
执行结果:
1号:我需要365秒的时间准备。 2号:我需要454秒的时间准备。 5号:我需要938秒的时间准备。 3号:我需要967秒的时间准备。 7号:我需要878秒的时间准备。 6号:我需要540秒的时间准备。 9号:我需要552秒的时间准备。 10号:我需要281秒的时间准备。 4号:我需要951秒的时间准备。 8号:我需要696秒的时间准备。 10号我已经准备完毕! 1号我已经准备完毕! 2号我已经准备完毕! 6号我已经准备完毕! 9号我已经准备完毕! 8号我已经准备完毕! 7号我已经准备完毕! 5号我已经准备完毕! 4号我已经准备完毕! 3号我已经准备完毕! 老大:所有准备完毕,开始... 2号:行动... 6号:行动... 1号:行动... 9号:行动... 8号:行动... 7号:行动... 10号:行动... 5号:行动... 4号:行动... 3号:行动... Process finished with exit code 0
countdownLatch也是也实现cycliBarrier珊拦结构,不过需要使用lock锁