什么是CountDownLatch:
CountDownLactch是一个同步工具类,用来协调线程之间的同步,其初始值是一个计数器,为线程的数量,当计时器的值为0时,代表此时所有线程的工作全部已经完成
常用方法:
1.countDown()
当一个线程任务完成时,即可调用countDown方法,使计数器的值-1
2.getCount()
获取当前计数器的值
3.await()
当所有计数器内的值变为0-----所有线程的任务都已经完成,此时可以执行其他操作,否则会阻塞等待
代码
public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(2); Thread t1 = new Thread(() -> { System.out.println("A"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); }); Thread t2 = new Thread(() -> { System.out.println("B"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); }); t1.start(); t2.start(); latch.await(); //System.out.println("主线程暂时被阻塞 latch计数器还不为0"); System.out.println("啦啦啦啦啦"); }
模拟跑步比赛
public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(8); //模拟八名运动员跑步 for循环内八个线程 抢占式调度 并不是按照i的顺序执行 //为什么运动时间是一个升序呢 大概一开始大家都只执行了算到了begin 就被其他线程抢夺了 //所以为了更模拟真实情况 我们应该要在最外面加一个锁 Object loker = new Object(); for(int i = 1; i <= 8; i++){ //lambda表达式中只能选用最终不可变的变量 //这里为什么不能使用i呢? //因为这里的i是变化的 由于线程的抢占式调度 每次执行的线程是不确定性的 故i也是不确定的 int j = i; new Thread(() -> { synchronized (loker){ try { long begin = System.currentTimeMillis(); Thread.sleep(new Random().nextInt(2000) + 3000); //3 - 5 秒 (模拟) long end = System.currentTimeMillis(); System.out.println("第"+j+"位运动员跑步时间为:"+(end - begin)+"ms"); } catch (InterruptedException e) { e.printStackTrace(); }finally { latch.countDown(); } } }).start(); } latch.await(); System.out.println("8名运动员已全部完成比赛 race over"); }
小结:
由上可知,CountDownLatch的主要作用为:
1.可以多个线程执行完后,再让某个线程执行
2.可以让多个线程并发执行,提高效率,实际案例中即下载比较大的文件, 可以分为多个线程都下载一小部分任务来完成