JAVA之并发编程(二) 2019-02-24 程序之旅 暂无评论 929 次阅读 在日常并发编程当中,我们往往会遇到这样一个问题,一个任务分配个多线程进行处理或多个模块对一个需求进行处理,并返回最终结果才能继续接下来的业务处理,但线程之间并不会进行互相等待,那么这个时候就需要一个计数器进行线程任务的记录。jdk中就直接有类似的实现,这工具就是CountDownLatch。 CountDownlatch的作用是一组线程等待其他的线程完成工作以后在执行,也就是加强版的join。在Countdownlatch中有两个比较常用的方法: - await():线程业务处理完成后,用来等待其他线程的完成 - countDown():负责对线程计数器减一,每完成有一个线程完成,数字就减一 ![countDownLatch.png][1] 在上图中就是Countdownlatch大概作用表现,假设你的程序中有三个线程A、B和C,并且线程同时运行处理业务,每个业务处理完成的时间不同,三个线程业务完成后的放回结果会同时影响下一步操作,这里就需要线程之间相互等待,然而我们不知道三个业务完成的优先级,所以必定会出现等待第三个结果出现的阻塞,这是Countdownlatch就突显其作用,在三个线程A、B和C线程完成后就在await方法后继续运行。我们来个例子: ``` import tool.SleepTools; import java.util.concurrent.CountDownLatch; /** * 测试Countdownlatch,有5个初始化的线程,6个扣除点 * 扣除完毕后,主线程才能继续自己的工作 */ public class UseCountDownLatch { static CountDownLatch latch = new CountDownLatch(6); private static class InitThread implements Runnable { @Override public void run() { System.out.println("InitThread_" + Thread.currentThread().getId() + " ready init work....."); latch.countDown(); System.out.println("InitThread_" + Thread.currentThread().getId() + "countinue do its work..."); } } // 业务线程 private static class BusiThread implements Runnable { @Override public void run() { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("BusiThread_" + Thread.currentThread().getId() + "do business-----"); } } public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { SleepTools.ms(1); System.out.println("Thread_" + Thread.currentThread().getId() + " ready init work step 1st..."); latch.countDown(); System.out.println("begin step 2nd..."); SleepTools.ms(1); System.out.println("Thread_" + Thread.currentThread().getId() + "ready init work step 3rd"); latch.countDown(); } }).start(); // 业务处理 new Thread(new BusiThread()).start(); for (int i = 0; i <= 3; i++) { Thread thread = new Thread(new InitThread()); thread.start(); } latch.await(); System.out.println("Main do ites work....."); } } ``` 执行代码运行结果为: ![countDownLatch2.png][2] 还有一个与Countdownlatch相反的工具类,也就是CyclicBarrier,该方法与Countdownlatch相同的是都有一个数值控制线程的开启或结束。CyclicBarrier的作用是让一组线程达到某个屏障,被阻塞,一直到组内最后一个线程达到屏障后,屏障开放,所有被阻塞的线程会继续运行。也就是在吃饭的时候等所有的人到齐了才开动。 ![CyclicBarrier.png][3] 这个挺好理解,直接上代码: ``` package com.xiangxue.ch2.tools; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CyclicBarrier; /** *类说明:CyclicBarrier的使用 */ public class UseCyclicBarrier { private static CyclicBarrier barrier = new CyclicBarrier(5,new CollectThread()); private static ConcurrentHashMap resultMap = new ConcurrentHashMap<>();//存放子线程工作结果的容器 public static void main(String[] args) { for(int i=0;i<=4;i++){ Thread thread = new Thread(new SubThread()); thread.start(); } } //负责屏障开放以后的工作 private static class CollectThread implements Runnable{ @Override public void run() { StringBuilder result = new StringBuilder(); for(Map.Entry workResult:resultMap.entrySet()){ result.append("["+workResult.getValue()+"]"); } System.out.println(" the result = "+ result); System.out.println("do other business........"); } } //工作线程 private static class SubThread implements Runnable{ @Override public void run() { long id = Thread.currentThread().getId();//线程本身的处理结果 resultMap.put(Thread.currentThread().getId()+"",id); Random r = new Random();//随机决定工作线程的是否睡眠 try { if(r.nextBoolean()) { Thread.sleep(2000+id); System.out.println("Thread_"+id+" ....do something "); } System.out.println(id+"....is await"); barrier.await(); Thread.sleep(1000+id); System.out.println("Thread_"+id+" ....do its business "); } catch (Exception e) { e.printStackTrace(); } } } } ``` [1]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/693117083.png [2]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/3805299383.png [3]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/3779644361.png 打赏: 微信, 支付宝 标签: 并发编程, java 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。