在java.util.concurrent包下有4个非常有用的并发工具类。CountDownLatch、CyclicBarrier提供了一种并发流程控制的手段。
1.CountDownLatch探究:
主要用到其两个实例方法:countDown()和await(),这两个方法配合使用,效果等同于Thread实例的join方法:
案例:有两个子线程,让这两个子线程执行完之后再执行主线程。
使用join:
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "执行");
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "执行");
}
}, "线程2");
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行");
}
使用CountDownLatch工具类:
public class DownCountLatchTest {
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "执行结束");
c.countDown();
}
}, "线程1").start();
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "执行结束");
c.countDown();
}
}, "线程2").start();
try {
c.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行");
}
}
以上,先创建CountDownLatch实例,只有一个构造器CountDownLatch(int count),需要传入一个正整数,这个正整数就代表计数器。在主线程中调用了CountDownLatch实例的await()方法,代表主线程阻塞,只有等计数器变为0的时候才会解除阻塞。而在每个子线程中都调用了CountDownLatch实例的countDown()方法,每调用一次CountDownLatch实例的countDown()方法,CountDownLatch实例的计数器就会减1,如果能减到0,则主线程解除阻塞,如果减不到0(比如一开始计数器是3,而两个子线程各自只调用了一次CountDownLatch实例的countDown()方法),则主线程会一直阻塞,所以在一开始创建CountDownLatch的实例时要设计好到底要传多大的数进去。
2.CyclicBarrier探究:
CyclicBarrier字面意思是可循环使用的屏障。它的作用是让一组线程到达一个屏障时被阻塞,直到指定数量的线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续往下执行。
public class CyclicBarrierTest {
static CyclicBarrier c = new CyclicBarrier(2);
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
try {
c.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行");
}
}, "线程1").start();
try {
c.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行");
}
}
以上,先用CyclicBarrier(int parties)构造器创建了一个会阻塞2个线程的CyclicBarrier实例。在子线程中和主线程中都调用了CyclicBarrier实例的await()方法,不管先在哪个线程中调用,该线程都会被屏障阻塞,直到CyclicBarrier实例的await()方法在另一个线程中被调用,之后屏障打开,两个线程剩下的代码接着执行。同CountDownLatch工具类相似的是,如果创建CyclicBarrier实例时传入的参数是3,而现在只有两个线程调用CyclicBarrier实例的await()方法,也就是只有两个线程会到达屏障,所有线程会一直被阻塞,因为还在等待第三个线程到达屏障,而一直等不到。
CyclicBarrier工具类还有一个构造器CyclicBarrier(int parties, Runnable barrierAction),需要传入一个正整数和一个Runnable对象,表示当屏障打开时,优先执行此Runnable对象。