在前面的两篇文章中我们分别用volatile、notify()和wait()分别实现了一个场景,我们再来回顾一下前面的场景:在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程结束,t1线程继续执行,直到循环结束。看过上篇文章的应该知道上篇文章我们是用notify()和wait()配合来实现线程之间的交互的,但是这种方法不是很好理解,而且写起来比较麻烦,在notify()之后必须要wait()才能立即释放锁,而且wait()方法执行之前必须是要先获得锁的,这就意味着wait()方法必须在synchronized方法或者是synchronized代码块之中来执行,这并不是很方便,本文中我们将用另一种更为简单且容易理解的方式来实现这个场景,下面直接看代码:
1 package com.fanjf.thread; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.CountDownLatch; 6 import java.util.concurrent.TimeUnit; 7 8 public class Mycontainer3 { 9 static List<Integer> integers = new ArrayList<>(); 10 final static Object object = new Object(); 11 static CountDownLatch latch = new CountDownLatch(1); 12 13 public static void main(String[] args) { 14 new Thread(new Runnable() { 15 public void run() { 16 System.out.println("t1启动"); 17 try { 18 TimeUnit.SECONDS.sleep(1); 19 } catch (InterruptedException e1) { 20 e1.printStackTrace(); 21 } 22 for(int i=0;i<10;i++){ 23 integers.add(i); 24 if(integers.size()==5){ 25 latch.countDown(); 26 } 27 try { 28 Thread.sleep(1000); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 System.out.println("add:"+i); 33 34 35 } 36 System.out.println("t1结束"); 37 38 } 39 }).start(); 40 41 new Thread(new Runnable() { 42 public void run() { 43 System.out.println("t2启动"); 44 try { 45 latch.await(); 46 } catch (InterruptedException e) { 47 e.printStackTrace(); 48 } 49 System.out.println("t2结束"); 50 51 52 } 53 54 }).start(); 55 } 56 57 }
执行结果如下:
1 t1启动 2 t2启动 3 add:0 4 add:1 5 add:2 6 add:3 7 t2结束 8 add:4 9 add:5 10 add:6 11 add:7 12 add:8 13 add:9 14 t1结束
很明显,这个结果跟我们的描述是一致的,现在来解释一下代码的意思,java并发包中为我们提供了一个CountDownLatch类,这个类的构造方法中可以传一个int值,首先线程t2执行await()方法,线程t1执行add操作,当size等于5时执行countDown(),这个countDown()会把传入的int值减1,只有当这个值减为0时,t2线程才能执行,所以当size等于5时此时值会减为0,t2就会继续执行了。