Java并发:CountDownLatch和CyclicBarrier使用记录

  日常开发中,我们常常需要处理大批量的数据,为了增加处理速度,提高程序执行效率,优先考虑到的是用多线程处理,这就涉及到要通过多线程去处理一件事或者一批数据,然后统计这些线程的处理结果。

除了使用线程的join()方法外,还可以使用CountDownLatch和CyclicBarrier这两个辅助工具,下面直接用代码说事,纯属个人使用心得,如有错误,欢迎指正。

一、使用线程的join()方法实现结果统计

Java代码:

 1 /**
 2  * @author goode
 3  * @date 2017-11-16 17:55:00
 4  */
 5   public class MyThread extends Thread{
 6 
 7     private Vector<String> vector;
 8 
 9     private Integer time;
10 
11     public MyThread(Vector<String> vector, Integer time) {
12         this.vector = vector;
13         this.time = time;
14     }
15 
16     public void run() {
17         System.out.println("==子线程" + Thread.currentThread().getName() + "开始执行...");
18         try {
19             vector.add(Thread.currentThread().getName());
20             Thread.sleep(time);
21         } catch (InterruptedException e) {
22             e.printStackTrace();
23         }
24         System.out.println("==子线程" + Thread.currentThread().getName() + "执行完毕");
25     }
26 }  

 

 1 public static void main(String[] args) {
 2        long start = System.currentTimeMillis();
 3        List<Thread> list = Lists.newArrayList();
 4        Vector<String> vector = new Vector<>();
 5        for (int i = 1; i <= 5; i++) {
 6            Thread thread = new MyThread(vector, i * 1000);
 7            thread.start();
 8            list.add(thread);
 9        }
10        try {
11            for (Thread thread : list) {
12                thread.join();//阻塞主线程
13            }
14        } catch (InterruptedException e) {
15            e.printStackTrace();
16        }
17        long end = System.currentTimeMillis();
18        System.out.println("====子线程执行时长:" + (end - start));
19        System.out.println("====多线程处理结果集长度:" + vector.size());
20    }

程序输出结果:

==子线程Thread-3开始执行...
==子线程Thread-1开始执行...
==子线程Thread-2开始执行...
==子线程Thread-0开始执行...
==子线程Thread-4开始执行...
==子线程Thread-0执行完毕
==子线程Thread-1执行完毕
==子线程Thread-2执行完毕
==子线程Thread-3执行完毕
==子线程Thread-4执行完毕
====子线程执行时长:5086
====多线程处理结果集长度:5
View Code

 

 二、使用CountDownLatch实现多线程处理数据

 Java代码:

 1 /**
 2  * @author goode
 3  * @date 2017-09-30 14:10:00
 4  */
 5 public class DoSomeThings implements Runnable {
 6 
 7     private CountDownLatch latch;
 8 
 9     private Integer time;
10 
11     private Vector<String> vector;
12 
13     public DoSomeThings(Vector<String> vector, CountDownLatch latch, int time) {
14         this.latch = latch;
15         this.time = time;
16         this.vector = vector;
17     }
18 
19 
20     @Override
21     public void run() {
22         System.out.println("====子线程" + Thread.currentThread().getName() + "开始执行...");
23         try {
24             Thread.sleep(time);
25             vector.add(Thread.currentThread().getName());
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         } finally {
29             latch.countDown();
30         }
31         System.out.println("====子线程" + Thread.currentThread().getName() + "执行完成,剩余执行中线程数据量:" + latch.getCount());
32     }
33 }

 

 1 public static void main(String[] args) {
 2         System.out.println("====主线程" + Thread.currentThread().getName() + "开始....");
 3         CountDownLatch latch = new CountDownLatch(5);
 4         ExecutorService es = Executors.newFixedThreadPool(5);
 5         Vector<String> list = new Vector<>();
 6         for (int i = 1; i <= 5; i++) {
 7             es.execute(new DoSomeThings(list, latch, i*1000));
 8         }
 9         try {
10             latch.await();
11         } catch (InterruptedException e) {
12             e.printStackTrace();
13         }
14         System.out.println("====主线程" + Thread.currentThread().getName() + "结束,获取处理后的数据长度=" + list.size());
15         es.shutdown();
16     }

程序输出结果:

====主线程main开始....
====子线程pool-1-thread-1开始执行...
====子线程pool-1-thread-2开始执行...
====子线程pool-1-thread-3开始执行...
====子线程pool-1-thread-4开始执行...
====子线程pool-1-thread-5开始执行...
====子线程pool-1-thread-1执行完成,剩余执行中线程数据量:4
====子线程pool-1-thread-2执行完成,剩余执行中线程数据量:3
====子线程pool-1-thread-3执行完成,剩余执行中线程数据量:2
====子线程pool-1-thread-4执行完成,剩余执行中线程数据量:1
====子线程pool-1-thread-5执行完成,剩余执行中线程数据量:0
====主线程main结束,获取处理后的数据长度=5
View Code

 

三、使用CyclicBarrier实现多线程处理数据

 Java代码: 

 1 /**
 2  * @author goode
 3  * @date 2017-09-30 14:10:00
 4  */
 5 public class DoThings extends Thread {
 6 
 7     private CyclicBarrier barrier;
 8 
 9     private Integer time;
10 
11     private Vector<String> vector;
12 
13     public DoThings(Vector<String> vector, CyclicBarrier barrier, int time) {
14         this.barrier = barrier;
15         this.time = time;
16         this.vector = vector;
17     }
18 
19     @Override
20     public void run() {
21         System.out.println("====子线程" + Thread.currentThread().getName() + "开始执行...");
22         try {
23             Thread.sleep(time);//程序处理其他业务逻辑
24             vector.add(Thread.currentThread().getName());
25             barrier.await();
26         } catch (BrokenBarrierException e) {
27             e.printStackTrace();
28         } catch (InterruptedException e) {
29             e.printStackTrace();
30         }
31         System.out.println("====子线程" + Thread.currentThread().getName() + "执行完成。");
32     }
33 
34 }

 

 1 public static void main(String[] args) {
 2         System.out.println("====主线程" + Thread.currentThread().getName() + "开始....");
 3         ExecutorService es = Executors.newFixedThreadPool(5);
 4         final Vector<String> vector = new Vector<>();
 5         CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
 6             @Override
 7             public void run() {
 8                 System.out.println("====所有子线程执行完毕,获取处理后的数据长度=" + vector.size());
 9             }
10         });
11         for (int i = 1; i <= 5; i++) {
12             es.execute(new DoThings(vector, barrier, i*1000));
13         }
14         es.shutdown();
15     }

 

程序处理结果: 

====主线程main开始....
====子线程pool-1-thread-1开始执行...
====子线程pool-1-thread-5开始执行...
====子线程pool-1-thread-3开始执行...
====子线程pool-1-thread-4开始执行...
====子线程pool-1-thread-2开始执行...
====所有子线程执行完毕,获取处理后的数据长度=5
====子线程pool-1-thread-5执行完成。
====子线程pool-1-thread-1执行完成。
====子线程pool-1-thread-2执行完成。
====子线程pool-1-thread-3执行完成。
====子线程pool-1-thread-4执行完成。
View Code

 

四、结果分析

  主要对比CountDownLatch和CyclicBarrier:

  1、使用场景

    从它们的的await()方法的位置即可看出,

    CountDownLatch是主线程wait所有子线程工作结束之后执行主线程。

    CyclicBarrier中是所有子线程之间相互wait,直到所有子线程就绪之后,如果有BarrierAction,则接着执行BarrierAction,最后再一起执行await()之后的程序。

  2、释放子线程资源时间点

    CountDownLatch中的每个子线程执行完之后,总线程统计计数减一,直到计数为0时释放所有等待的线程,不可重用。

    CyclicBarrier中的每个子线程执行完之后,总线程统计计数加一,直到计数达到指定值时释放所有等待的线程。计数达到指定值时,计数置为0重新开始,以达到 CyclicBarrier重用的功能。

  3、异常处理

    CountDownLatch中某个子线程中遇到异常,不影响其他子线程运行。

    CyclicBarrier中某个子线程中遇到异常,其他子线程也将抛出异常。

  4、建议:

    如果业务需求非常严谨,不允许任何一个子线程出行异常,则应该使用CyclicBarrier较为妥当,而如果CyclicBarrier的BarrierAction不依赖于其他子线程运行的结果,

    则任何一个线程被释放的之后,即可直接运行这个Action(可用barrier.await()==2判断)。

    实际使用过程中,可根据业务需求,适当调整countDown()、await()方法所在程序中的位置,可达到事半功倍的效果。

 

转载于:https://www.cnblogs.com/goode/p/7845617.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值