【Java Concurrent Programming 】 Limited time CountDownLatch parallel scenarios

Like is the best encouragement to create!

Service Scenario:

A user data interface requires to return data within 20ms. Its call logic is complex and there are many associated interfaces, so data needs to be summarized from three interfaces. The minimum time for summarizing these interfaces is 16ms, and the time for summarizing the optimal state of all interfaces is 16ms*3=48ms

Solution:

Using the parallel call interface, the result set is obtained by multiple threads at the same time, and finally the result is integrated. In this scenario, the CountDownLatch of the Concurrent package is used. CountDownLatch is essentially a counter, initializing it to the same number of tasks that are executed, and when a task is completed, subtracted the counter value by 1 until the calculator reaches 0, indicating that all tasks have been completed, and the waiting thread on the await continues execution.

For the utility class encapsulated in the above business scenario, pass two parameters: one parameter is the number of tasks to calculate and the other parameter is the number of milliseconds the entire large task times out.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ParallelCollector {

    private Long timeout;
    private CountDownLatch countDownLatch;
    ThreadPoolExecutor executor = new ThreadPoolExecutor(100.200.1, TimeUnit.HOURS, new ArrayBlockingQueue<>(100));

    public ParallelCollector(int taskSize, Long timeOutMill) {
        countDownLatch = new CountDownLatch(taskSize);
        timeout = timeOutMill;
    }

    public void submitTask(Runnable runnable) {
        executor.execute(() -> {
            runnable.run();
            countDownLatch.countDown();
        });
    }

    public void await(a) {
        try {
            this.countDownLatch.await(timeout, TimeUnit.MILLISECONDS);
        } catch(InterruptedException e) { e.printStackTrace(); }}public void destroy(a) {
        this.executor.shutdown(); }}Copy the code

The function of await() is to stop the task directly when it has exceeded the time limit of the task.

Interface is a test class that simulates the timeout of a remote service. When the program runs, it outputs the execution results to a map set.

public class InterfaceMock {
    private  volatile  int num=1;

   public String slowMethod1(a) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return String.valueOf(num+1);
    };

   public String slowMethod2(a) {
        return String.valueOf(num+1);
    };

   public String slowMethod3(a) {
        return String.valueOf(num+1);
    };
}
Copy the code

Parallel execution of test classes to get results

@SpringBootTest
class ThreadPoolApplicationTests {
    @Test
    void testTask(a) {
        InterfaceMock interfaceMock = new InterfaceMock();
        ParallelCollector collector = new ParallelCollector(3.20L);
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
        collector.submitTask(()->map.put("method1",interfaceMock.slowMethod1()));
        collector.submitTask(()->map.put("method2",interfaceMock.slowMethod2()));
        collector.submitTask(()->map.put("method3",interfaceMock.slowMethod3())); collector.await(); System.out.println(map.toString()); collector.destroy(); }}Copy the code

When the execution time of method1() is longer than 20ms, the method is terminated directly, and the resulting map set does not have the result of method1(), which is as follows:

conclusion

In this way, the interface can be returned in a fixed amount of time. Note that CountDownLatch defines the number of tasks. Using concurrentHashMap avoids the problem of concurrent execution errors, resulting in incorrect results.