Recently, I met a requirement, one of which is time-consuming. In order to improve efficiency, I choose to start a new thread asynchronously. Due to the need to operate on the return value of the method, I choose to use FutureTask, which can get the task circularly and call the get method to get the execution result of the task. However, if the task is not completed, the thread to get the result will block until the task is completed. Later, the CompletionService class was discovered, which integrates the functions of Executor and BlockingQueue. You can submit the Callable task to it for execution, and then use the take method similar to the queue to get the return value of the thread.
The demo is as follows:
package com.aliyun.callback; import org.junit.Test; import java.util.Random; import java.util.concurrent.*; /** * Created by Demon, on 2018/4/25 */ public class CompletionServiceTest { private static final int DEFAULT_CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() <= 1 ? 2 : Runtime.getRuntime().availableProcessors() * 2; private static final int DEFAULT_MAXNUM_POOL_SIZE = 32; private static final int DEFAULT_KEEP_ALIVE_TIME = 30; private ThreadPoolExecutor threadPool = new ThreadPoolExecutor(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAXNUM_POOL_SIZE , DEFAULT_KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20)); @Test public void test() { CompletionService<String> completionService = new ExecutorCompletionService<>(threadPool); try { for (int i = 0; i < 5; i++) { Task task = new Task("threadName" + i); // Using submit main thread can catch exceptions in asynchronous thread completionService.submit(task); } } catch (Exception e) { e.printStackTrace(); } for (int i = 0; i < 5; i++) { try { Future<String> future = completionService.take(); System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } private class Task implements Callable<String> { private String name; private Task(String name) { this.name = name; } @Override public String call() throws Exception { int sleepTime = new Random().nextInt(1000); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } // Value returned to the caller String str = name + " sleep time:" + sleepTime; System.out.println(name + " finished..."); // throw new RuntimeException("test catch error"); return str; } } } //Operation result: threadName0 finished... threadName0 sleep time:140 threadName4 finished... threadName4 sleep time:250 threadName3 finished... threadName3 sleep time:258 threadName1 finished... threadName1 sleep time:416 threadName2 finished... threadName2 sleep time:712
When using CompletionService to maintain the return results of processing threads, the main thread can always get the return value of the first completed task, regardless of the order in which they are added to the thread pool, which can reduce the blocking time of the main thread and is better than the native future.get method.