博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CountDownLatch多任务并行处理
阅读量:7118 次
发布时间:2019-06-28

本文共 3180 字,大约阅读时间需要 10 分钟。

前言:

最近在做一个原始数据统计的功能,用户通过前台设置相关参数,后台实时统计并返回数据。

  • 数据排名
  • 求和、最大、最小
  • 统计类比

最好的用户体验,就是每一个操作都可以实时的展示数据,3秒之内应该是用户的忍受范围之内的了,所以做一款产品不仅要考虑用户交互设计,后端的优化也是比不可少的。最主要的还是要实时、实时、实时。

改造前

程序逻辑

改造后

程序逻辑

多任务并行处理,适用于多核CPU,单核CPU多线程执行任务可能会适得其反(上下文切换以及线程的创建和销毁都会消耗资源),特别是CPU密集型的任务。

代码示例:

public class StatsDemo {    final static SimpleDateFormat sdf = new SimpleDateFormat(            "yyyy-MM-dd HH:mm:ss");        final static String startTime = sdf.format(new Date());    public static void main(String[] args) throws InterruptedException {        CountDownLatch latch = new CountDownLatch(5);// 两个赛跑者        Stats stats1 = new Stats("任务A", 1000, latch);        Stats stats2 = new Stats("任务B", 2000, latch);        Stats stats3 = new Stats("任务C", 2000, latch);        Stats stats4 = new Stats("任务D", 2000, latch);        Stats stats5 = new Stats("任务E", 2000, latch);        stats1.start();//任务A开始执行        stats2.start();//任务B开始执行        stats3.start();//任务C开始执行        stats4.start();//任务D开始执行        stats5.start();//任务E开始执行        latch.await();// 等待所有人任务结束        System.out.println("所有的统计任务执行完成:" + sdf.format(new Date()));    }    static class Stats extends Thread {        String statsName;        int runTime;        CountDownLatch latch;        public Stats(String statsName, int runTime, CountDownLatch latch) {            this.statsName = statsName;            this.runTime = runTime;            this.latch = latch;        }        public void run() {            try {                System.out.println(statsName+ " do stats begin at "+ startTime);                //模拟任务执行时间                Thread.sleep(runTime);                System.out.println(statsName + " do stats complete at "+ sdf.format(new Date()));                latch.countDown();//单次任务结束,计数器减一            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}复制代码
任务B do stats begin at 2019-06-13 16:46:18任务D do stats begin at 2019-06-13 16:46:18任务E do stats begin at 2019-06-13 16:46:18任务C do stats begin at 2019-06-13 16:46:18任务A do stats begin at 2019-06-13 16:46:18任务A do stats complete at 2019-06-13 16:46:19任务E do stats complete at 2019-06-13 16:46:20任务B do stats complete at 2019-06-13 16:46:20任务C do stats complete at 2019-06-13 16:46:20任务D do stats complete at 2019-06-13 16:46:20所有的统计任务执行完成:2019-06-13 16:46:20复制代码

总结

1.CountDownLatch用于同步一个或多个任务,强制他们等待由其他任务执行的一组操作完成。CountDownLatch典型的用法是将一个程序分为N个互相独立的可解决任务,并创建值为N的CountDownLatch。当每一个任务完成时,都会在这个锁存器上调用countDown,等待问题被解决的任务调用这个锁存器的await,将他们自己拦住,直至锁存器计数结束。

1.1 使用注意

  • 在创建实例时,必须指定初始的计数值,且应大于0
  • 必须有线程中显示的调用了countDown()计数-1方法;必须有线程显示调用了await()方法(没有这个就没有必要使用CountDownLatch了)
  • 由于await()方法会阻塞到计数为0,如果在代码逻辑中某个线程漏掉了计数-1,导致最终计数一直大于0,直接导致死锁了;
  • 鉴于上面一点,更多的推荐 await(long, TimeUnit)来替代直接使用await()方法,至少不会造成阻塞死只能重启的情况
  • 允许多个线程调用await方法,当计数为0后,所有被阻塞的线程都会被唤醒

2. 实现原理

await内部实现流程:

  1. 判断state计数是否为0,不是,则直接放过执行后面的代码
  2. 大于0,则表示需要阻塞等待计数为0
  3. 当前线程封装Node对象,进入阻塞队列
  4. 然后就是循环尝试获取锁,直到成功(即state为0)后出队,继续执行线程后续代码

countDown内部实现流程:

  1. 尝试释放锁tryReleaseShared,实现计数-1
  • 若计数已经小于0,则直接返回false
  • 否则执行计数(AQS的state)减一
  • 若减完之后,state==0,表示没有线程占用锁,即释放成功,然后就需要唤醒被阻塞的线程了
  1. 释放并唤醒阻塞线程 doReleaseShared
  • 如果队列为空,即表示没有线程被阻塞(也就是说没有线程调用了 CountDownLatch#wait()方法),直接退出

转载于:https://juejin.im/post/5d070517f265da1b827a9bb1

你可能感兴趣的文章
Linux笔记(shell特殊符号,sort排序,wc统计,uniq去重,tee,tr,split)
查看>>
11.15PMP试题每日一题
查看>>
华为模拟器如何实现不同Vlan不同网段之间的互通
查看>>
PHP 实现Session入库/存入redis
查看>>
kubernetes集群搭建
查看>>
Spring MVC 入门指南(二):@RequestMapping用法详解
查看>>
motion加树莓派打造实时监控
查看>>
详解MySQL基准测试和sysbench工具
查看>>
使用Spring Session和Redis解决分布式Session跨域共享问题
查看>>
手机锁屏密码忘记了怎么办,清除锁屏的办法
查看>>
BVS烟火识别输油站烟火检测应用
查看>>
使用Apache Ignite构建C++版本的分布式应用
查看>>
数据库基本概念
查看>>
恢复后缀ETH勒索病毒解密方法 恢复sql文件.com].ETH
查看>>
找到dht网络的节点了
查看>>
国内整C多IP服务器怎么搭建代理IP,又怎么区分代理IP呢
查看>>
人工智能+教育的应用——教育的安全
查看>>
一种面包屑导航
查看>>
shell脚本练习
查看>>
pdf页眉页脚设置步骤
查看>>