java并发之CountDownLatch

java

一、简介

CountDownlatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

它本身而言是Java并发包中非常有用的一个类,它可以让某些任务完成以后再继续运行下面的内容,每个任务本身执行完毕后让计数器减一,直到计数器清零后,以下的内容才可以继续运行,否则将阻塞等待。

二、应用场景

想了一下,这个场景非常适合用于项目中这样的场景: 我们有个项目,它需要三个第三方的API,并把结果拿到,在一个线程中顺序去拿结果没有问题,但是这里这三个任务是非常耗时的操作,如果顺序获取性能非常差,因此可以考虑用三个线程,当三个线程拿到结果后才继续主线程的工作,等三个线程运行结束后,由主线程去取子线程运行的结果。 这里有个很重要的前提:我们的系统运行在4个cpu的server上,这样多线程才能体现性能,JVM会分配这些线程尽量运行在不同的cpu上。

CountDownLatch有以下基本方法:

1)await(),阻塞等待,直到计数器清零

2)await(int timeout, TimeUnit unit),使线程阻塞,除非被中断或者超过等待的最大时间。如果达到计数器清零,则await返回true,如果等待超过了最大的等待时间,则返回false。

3)countDown(),计数器减一,当计数器清零时,await的线程被唤醒,线程继续执行

4)getCount(),获取当前计数器的大小

代码示例

现在模拟一个业务场景,就是页面上的列表数据导出,通常的做法是根据查询条件从数据库,然后把查询的数据再逐个写到excel文件里,正常情况这样做是没问题的,但是如果数据量很大,还在一个线程里操作的话,将会非常耗时。这时我们可以根据实际情况,比方说新建三个线程,这三个线程把整个要处理的数据拆分成三段分别同时处理,然后主线程等这三个线程都处理完了再进行整合这三部分的操作。

那么问题来了,怎么才能确保主线程始终能等这三个业务线程执行完了再执行呢?

 1 public class Test {

2

3 public static void main(String[] args) throws IOException {

4 // 模拟数据库资源

5 CopyOnWriteArrayList<Integer> ziyuan = new CopyOnWriteArrayList<Integer>();

6 for (int i = 1; i < 10; i++) {

7 ziyuan.add(i);

8 }

9 ExecutorService executorService = Executors.newCachedThreadPool();

10 // 标记一共有ziyuan.size()/3个线程需要等待

11 CountDownLatch cLatch = new CountDownLatch(ziyuan.size()/3);

12 // 开启三个线程

13 for (int i = 0; i < ziyuan.size()/3; i++) {

14 executorService.execute(new TaskRunn(ziyuan,cLatch, 3*i));

15 }

16 // 关闭线程池

17 executorService.shutdown();

18 // 主线程等待

19 try {

20 cLatch.await();

21 } catch (InterruptedException e) {

22 e.printStackTrace();

23 }

24 System.out.println("我是主线程要操作的内容,必须确保我在其它三个线程执行完后最后打印。。。");

25 }

26 }

27

28 class TaskRunn implements Runnable{

29

30 private CopyOnWriteArrayList<Integer> ziyuan;

31 private CountDownLatch cLatch;

32 private int c;

33 public TaskRunn(CopyOnWriteArrayList<Integer> ziyuan,CountDownLatch cLatch,int c) {

34 this.ziyuan = ziyuan;

35 this.cLatch = cLatch;

36 this.c = c;

37 }

38

39 @Override

40 public void run() {

41 System.out.println(Thread.currentThread().getName()+"begin...");

42 for (int i = c; i < ziyuan.size()/3+c; i++) {

43 System.out.println(Thread.currentThread().getName()+"//"+ziyuan.get(i)+"//CountDownLatch:"+cLatch.getCount());

44 try {

45 Thread.sleep(new Random().nextInt(4)*1000);// 模拟业务耗时

46 } catch (InterruptedException e) {

47 e.printStackTrace();

48 }

49 }

50 System.out.println(Thread.currentThread().getName()+"end...");

51 // 每个业务线程执行完后会减去1

52 cLatch.countDown();

53 }

54

55 }

如果把上面代码红色字体部分注释掉,那结果就不会这样了。。。

注意点

在实际开发中,为了防止发生异常时cLatch.countDown()没有执行到,所以最好把它放到finally里。。

以上是 java并发之CountDownLatch 的全部内容, 来源链接: utcz.com/z/394212.html

回到顶部