jdk1.5的concurrent包为我们提供了很多有用的辅助类,今天我们来学习一下
一、闭锁CountDownLatch
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步。它的作用是,在完成某些运算时,只有其他所有线程的运算全部完成,当前线程的运算才继续执行。
CountDownLatch类只提供了一个构造器:
1
2
3 1public CountDownLatch(int count) { }; //参数count为计数值
2
3
然后下面这3个方法是CountDownLatch类中最重要的方法:
1
2
3
4
5 1public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
2public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
3public void countDown() { }; //将count值减1
4
5
接下来我们看看下面的这个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 1public class TestCountDownLatch {
2
3 public static void main(String[] args) {
4 final CountDownLatch latch = new CountDownLatch(50);
5 LatchDemo ld = new LatchDemo(latch);
6
7 long start = System.currentTimeMillis();
8
9 for (int i = 0; i < 50; i++) {
10 new Thread(ld).start();
11 }
12
13 try {
14 latch.await();
15 } catch (InterruptedException e) {
16 }
17
18 long end = System.currentTimeMillis();
19
20 System.out.println("耗费时间为:" + (end - start));
21 }
22
23}
24
25class LatchDemo implements Runnable {
26
27 private CountDownLatch latch;
28
29 public LatchDemo(CountDownLatch latch) {
30 this.latch = latch;
31 }
32
33 @Override
34 public void run() {
35
36 try {
37 for (int i = 0; i < 50000; i++) {
38 if (i % 2 == 0) {
39 System.out.println(i);
40 }
41 }
42 } finally {
43 latch.countDown();
44 }
45
46 }
47
48}
49
50
通过CountDownLatch,我们就可以计算一批线程的执行时间。从这个例子中我们也可以看出:CountDownLatch中维护了一个int类型的变量。当前线程调用await()方法来使用这个辅助类,在这个变量成为0之后当前线程就会继续执行下去了。所以我们在构造器里填入的变量要跟等待的线程数量相同。
二、CyclicBarrier
1
2
3 1CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
2
3
CyclicBarrier提供2个构造器:
1
2
3
4
5
6
7 1public CyclicBarrier(int parties, Runnable barrierAction) {
2}
3
4public CyclicBarrier(int parties) {
5}
6
7
参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
然后CyclicBarrier中最重要的方法就是await方法,它有2个重载版本:
1
2
3
4 1public int await() throws InterruptedException, BrokenBarrierException { };
2public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };
3
4
第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;
第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 1public class Test {
2 public static void main(String[] args) {
3 int N = 4;
4 CyclicBarrier barrier = new CyclicBarrier(N);
5 for(int i=0;i<N;i++)
6 new Writer(barrier).start();
7 }
8 static class Writer extends Thread{
9 private CyclicBarrier cyclicBarrier;
10 public Writer(CyclicBarrier cyclicBarrier) {
11 this.cyclicBarrier = cyclicBarrier;
12 }
13
14 @Override
15 public void run() {
16 System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
17 try {
18 Thread.sleep(5000); //以睡眠来模拟写入数据操作
19 System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
20 cyclicBarrier.await();
21 } catch (InterruptedException e) {
22 e.printStackTrace();
23 }catch(BrokenBarrierException e){
24 e.printStackTrace();
25 }
26 System.out.println("所有线程写入完毕,继续处理其他任务...");
27 }
28 }
29}
30
31
执行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1线程Thread-0正在写入数据...
2线程Thread-3正在写入数据...
3线程Thread-2正在写入数据...
4线程Thread-1正在写入数据...
5线程Thread-2写入数据完毕,等待其他线程写入完毕
6线程Thread-0写入数据完毕,等待其他线程写入完毕
7线程Thread-3写入数据完毕,等待其他线程写入完毕
8线程Thread-1写入数据完毕,等待其他线程写入完毕
9所有线程写入完毕,继续处理其他任务...
10所有线程写入完毕,继续处理其他任务...
11所有线程写入完毕,继续处理其他任务...
12所有线程写入完毕,继续处理其他任务...
13
14
CyclicBarrier和CountDownLatch的区别
- CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器是可以重用的。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
- CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。
参考文章
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- 并发工具类(二)同步屏障CyclicBarrier
本文作者: catalinaLi
本文链接: http://catalinali.top/2018/helloLatch/