Preface:

Recently, we are doing a function of raw data statistics. The user sets relevant parameters through the foreground, and the background makes real-time statistics and returns data.

  • The data in
  • Sum, Max, min
  • Statistical analogy

The best user experience is that every operation can display data in real time, within 3 seconds should be within the tolerance range of users. Therefore, to make a product, not only user interaction design should be considered, but also back-end optimization is indispensable. The main thing is real time, real time, real time.

Before modification

The program logic


After transforming

The program logic

Multi-task parallel processing, suitable for multi-core cpus, single-core CPUS multi-threading tasks can be counterproductive (context switching and thread creation and destruction consume resources), especially CPU-intensive tasks.

Code examples:

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); Stats1 = new Stats("The task A", 1000, latch);
        Stats stats2 = new Stats("The task B", 2000, latch);
        Stats stats3 = new Stats("The task C", 2000, latch);
        Stats stats4 = new Stats(Task "D", 2000, latch);
        Stats stats5 = new Stats(Task "E", 2000, latch); stats1.start(); // Task A starts executing stats2.start(); // Task B starts executing stats3.start(); // Task C starts executing stats4.start(); // Task D starts stats5.start(); // Task E starts latching. Await (); System.out.println(system.out.println ("All statistical tasks completed :" + 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(); }}}}Copy the code

Task BdoStats begin at 2019-06-13 16:46:18 Task DdoStats begin at 2019-06-13 16:46:18 Task EdoStats begin at 2019-06-13 16:46:18 Task CdoStats begin at statsdoStats begin at statsdoStats Complete at 2019-06-13doStats Complete at 2019-06-13 task BdoStats Complete at 2019-06-13doStats Complete at 2019-06-13doAll stats complete at 2019-06-13 16:46:20Copy the code

conclusion

1.CountDownLatch is used to synchronize one or more tasks, forcing them to wait for a set of actions performed by other tasks to complete. The typical use of CountDownLatch is to divide an application into N independently solvable tasks and create countdownLatches of value N. CountDown is called on the store when each task is complete, and tasks waiting for the problem to be resolved call await of the store and block themselves until the count of the store ends.

1.1 Usage Precautions

  • When creating an instance, you must specify an initial count value that is greater than 0
  • There must be a call displayed in the threadcountDown()Counting -1 method; There must be a thread to display the callawait()Method (without this there is no need for CountDownLatch)
  • Since the await() method blocks until the count is 0, if a thread in the code logic misses count -1, the final count will always be greater than 0, resulting in a deadlock.
  • In view of the above, more recommendationsawait(long, TimeUnit)Instead of using it directlyawait()Method, at least not cause blocking death can only restart the situation
  • Allows multiple threads to callawaitMethod, when the count is 0, all blocked threads are woken up

2. Implementation principle

Await internal implementation process:

  1. Determine if the state count is 0, and if it is not, skip the code that follows
  2. If the value is greater than 0, the waiting count for blocking is 0
  3. The current thread encapsulates the Node object and enters the blocking queue
  4. It then loops through attempts to acquire the lock until it succeeds (i.e., state is 0) and exits the queue to continue executing the thread’s subsequent code

CountDown internal implementation process:

  1. Attempt to release the locktryReleaseShared, to implement the count -1
  • If the count is already less than 0, return false
  • Otherwise, the execution count (state of AQS) is reduced by one
  • If state==0, it means that no thread is holding the lock, that is, it is released successfully, and then it needs to wake up the blocked thread
  1. Release and wake up the blocking threaddoReleaseShared
  • If the queue is empty, no threads are blocked (that is, no threads called CountDownLatch#wait()) and exit