Java并发编程之CountDownLatch的用法
一、含义
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。CountDownLatch
是一个同步的辅助类,它可以允许一个或多个线程等待,直到一组在其它线程中的操作执行完成。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
二、原理
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
三、CountDownLatch类的方法
CountDownLatch类只提供了一个构造器:
public
CountDownLatch(
int
count) { };
//参数count为计数值
构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。
然后下面这3个方法是CountDownLatch类中最重要的方法:
1 public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行 2 3 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行 4 5 public void countDown() { }; //将count值减1
注意:
一个countDownLatch的作用只能使用一次,当counDownLatch对象的计数器被初始化之后不能再次初始化或者修改。当调用countDown()方法使count为0时,await()方法阻塞的线程都会被唤醒执行,之后再使用countDown()等方法已经没有用了,CountDownLatch对象也就没有用了。
一个countDownLatch的作用只能使用一次,当counDownLatch对象的计数器被初始化之后不能再次初始化或者修改。当调用countDown()方法使count为0时,await()方法阻塞的线程都会被唤醒执行,之后再使用countDown()等方法已经没有用了,CountDownLatch对象也就没有用了。
下面看一个例子大家就清楚CountDownLatch的用法了:
1 public class Test { 2 public static void main(String[] args) { 3 final CountDownLatch latch = new CountDownLatch(2); 4 5 new Thread(){ 6 public void run() { 7 try { 8 System.out.println("子线程"+Thread.currentThread().getName()+"正在执行"); 9 Thread.sleep(3000); 10 System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕"); 11 latch.countDown(); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 }; 16 }.start(); 17 18 new Thread(){ 19 public void run() { 20 try { 21 System.out.println("子线程"+Thread.currentThread().getName()+"正在执行"); 22 Thread.sleep(3000); 23 System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕"); 24 latch.countDown(); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 }; 29 }.start(); 30 31 try { 32 System.out.println("等待2个子线程执行完毕..."); 33 latch.await(); 34 System.out.println("2个子线程已经执行完毕"); 35 System.out.println("继续执行主线程"); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 } 40 }
执行结果:
1 线程Thread-0正在执行 2 线程Thread-1正在执行 3 等待2个子线程执行完毕... 4 线程Thread-0执行完毕 5 线程Thread-1执行完毕 6 2个子线程已经执行完毕 7 继续执行主线程