About multithreaded calculations Synchronization

Foreword

Daily moving bricks, got a job in the business logic optimization serial call RPC service (do not ask me why I do not understand serial), through painstaking reflection, I ask students surrounding the great God, filled with wisdom, with this article .

Multi-mode thread gets results

The thought of another multi-threaded query data summary, I think of three ways, and to select the optimal solution based on business performance.

Future synchronous

  • Future synchronous, surely we all know, is the getmethod, source code comments below.

Waits if necessary for the computation to complete, and then retrieves its result interpretation:. Future.get () before the end of the thread computing, it has been in a wait state.

Code

public static void main(String[] args) throws InterruptedException, ExecutionException {
        long l = System.currentTimeMillis();
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        Future<Integer> future = executorService.submit(() -> {
            System.out.println("执行耗时操作...");
            timeConsumeOp();
            // 耗时3000ms
            return 100;
        });

        Future<Integer> future1 = executorService.submit(() -> {
            System.out.println("执行耗时操作1...");
            // 耗时2000ms
            timeConsumeOp1();
            return 101;
        });

		// 依次将future、future1添加进列表
        List<Future<Integer>> futureList = Lists.newArrayList(future, future1);
        int s = 0;
        for (Future<Integer> future2 : futureList) {
	        // 线程计算结果
	        System.out.println("返回结果:" + future2.get());
            s = s + future2.get();
        }
        // 求和
        System.out.println("计算结果:" + s);
        // 主线程耗时
        System.out.println("主线程耗时:" + (System.currentTimeMillis() - l));
    }

    private static void timeConsumeOp() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void timeConsumeOp1() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
复制代码
  • result
执行耗时操作...
执行耗时操作1...
返回结果:100
返回结果:101
计算结果:201
主线程耗时:3077
复制代码

Resolve

  • Call is synchronous , time-consuming it can be seen from the main thread, the main thread in a wait state, waiting for the results to return only started to run , and therefore takes about 3000ms.

  • Get the result depends on the calling sequence , although the future1calculation time than futureshorter (2000ms <3000ms), should be obtained first and then get 101 100, but Future.get()depends on calling sequence as traversed futureListduring the first call futureof the getmethod.

  • We will be futureListthe order of elements replaced, look at the results.

// 先future1
List<Future<Integer>> futureList = Lists.newArrayList(future1, future);
复制代码
  • result
执行耗时操作...
执行耗时操作1...
返回结果:101
返回结果:100
计算结果:201
主线程耗时:3076
复制代码

CompletionService

  • CompletionServiceUse excutorrealization of task execution, add LinkedBlockingQueuethe completed FutureTaskadded.
	// 使用线程数为2的线程池初始化
    private static CompletionService<Integer> completionService = new ExecutorCompletionService<> (Executors.newFixedThreadPool(2));
复制代码

Code

public static void main(String[] args) throws InterruptedException, ExecutionException {
        long l = System.currentTimeMillis();
        
        Future<Integer> future = completionService.submit(() -> {
            System.out.println("执行耗时操作...");
            timeConsumeOp();
            return 100;
        });

        Future<Integer> future1 = completionService.submit(() -> {
            System.out.println("执行耗时操作1...");
            timeConsumeOp1();
            return 101;
        });

        int s = 0;

        for (int i = 0; i < 2; i++) {
            int result = completionService.take().get();
            System.out.println("返回结果:" + result);
            s += result;
        }

        System.out.println("计算结果:" + s);
        System.out.println("主线程耗时:" + (System.currentTimeMillis() - l));
    }

    private static void timeConsumeOp() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void timeConsumeOp1() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
复制代码
  • result
执行耗时操作...
执行耗时操作1...
返回结果:101
返回结果:100
计算结果:201
主线程耗时:3066
复制代码

Resolve

  • Call is synchronous , time-consuming it can be seen from the main thread, the main thread in a wait state, waiting for the results to return only started to run , and therefore takes about 3000ms.
  • Get the result depends on the order of calculation is completed , although the future1calculation time than futureshorter (2000ms <3000ms), then thus obtained to give 101 100.

Future callback type + CountDownLatch

Future callback type

  • There are many ways to achieve Future callback style, Guavait provides two ways ListeningExecutorService, CompletableFutureit can also be used Nettyin Future.
  • Understanding the callback type, Android development experience comes into play, in fact, asynchronous calls, like Android responsible for rendering in the main thread, the thread access to the network to get the results of the callback trigger the main thread to modify UI.
  • As used herein CompletableFutureimplementation, we are interested can use in other ways.

CountDownLatch(CycleBarrier)

  • CountDownLatch similar to "counter" countdown()method would "counter" minus one, calling the await()thread in the "counter" to 0 before, in a wait state.

The result is stored

  • Correction calculation formula is characterized by the return of the working thread, so to synchronize the results can be used concurrentset, or using similar Map<AtomicInteger,Object>data results are summarized the results of the respective sub-threads.

Code

public static void main(String[] args) throws Exception{
        CountDownLatch countDownLatch = new CountDownLatch(2);

        List<Integer> list = Collections.synchronizedList(new ArrayList<>(2));
        long l = System.currentTimeMillis();
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行耗时操作...");
            timeConsumeOp();
            return 100;
        });
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("执行耗时操作1...");
                timeConsumeOp1();
                return 101;
            }
        });

        completableFuture.whenComplete((integer, throwable) -> {

            if (throwable != null) {
                System.out.println("运行错误");
            } else {
                System.out.println("计算结果:" + integer + " 线程名:" + Thread.currentThread().getName());
                list.add(integer);
            }
            countDownLatch.countDown();

        });

        completableFuture1.whenComplete((integer, throwable) -> {

            if (throwable != null) {
                System.out.println("运行错误");
            } else {
                System.out.println("计算结果:" + integer + " 线程名:" + Thread.currentThread().getName());
                list.add(integer);
            }
            countDownLatch.countDown();
        });


        System.out.println("计算结果汇总前 主线程还在运行:" + (System.currentTimeMillis() - l));
        // 主线程等待
        countDownLatch.await();

        int s = 0;
        for (int i : list) {
            s += i;
        }
        System.out.println("计算结果为:" + s + " 耗时 " + (System.currentTimeMillis() - l));
    }
复制代码
  • result
执行耗时操作...
执行耗时操作1...
计算结果汇总前 主线程还在运行:70
计算结果:101 线程名:ForkJoinPool.commonPool-worker-2
计算结果:100 线程名:ForkJoinPool.commonPool-worker-1
计算结果为:201 耗时 3072
复制代码

Resolve

  • Callback type, that is asynchronous call does not make the main thread in a wait state.
  • countDownLatch.countDown()After calculating the time to store the results, otherwise the result may miss the thread running.
  • countDownLatch.await()The main thread will wait for all the threads countDown, it begins to run, you can see time-consuming.
  • Use the Collections.synchronizedListreason for the return results in different threads, memory lock guarantee results.

Epilogue

This article combines several programs I can think of, and a brief analysis, people are not always right, we have a better solution, I can communicate with the author.

references

www.cnkirito.moe/future-and-…

Guess you like

Origin juejin.im/post/5d5556df6fb9a06acf2b5597