前言:
最近在做一个原始数据统计的功能,用户通过前台设置相关参数,后台实时统计并返回数据。
最好的用户体验,就是每一个操作都可以实时的展示数据,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 使用注意
countDown() 计数-1方法;必须有线程显示调用了 await() 方法(没有这个就没有必要使用CountDownLatch了) await(long, TimeUnit) 来替代直接使用 await() 方法,至少不会造成阻塞死只能重启的情况 await 方法,当计数为0后,所有被阻塞的线程都会被唤醒 2. 实现原理
await内部实现流程:
countDown内部实现流程:
tryReleaseShared ,实现计数-1 doReleaseShared