CompletionService
The function of the interface CompletionService is to produce new tasks asynchronously while processing the results of completed tasks, so that the execution tasks can be separated from the processing tasks for processing. Use submit to perform tasks, use take to get completed tasks, and process their results in the order in which they were completed.
The structure of the interface Completion Service is relatively simple. There is only one implementation class, Executor Completion Service. The construction method of this class is shown in the figure.
From the declaration of the constructor, it can be found that the Executor Completion Service class needs to rely on the Executor object, and most of the implementation uses the thread pool ThreadPoolExecutor object.
take() method
public class TestDemo { public static void main(String[] args) { try { //take: get and remove the Futrue of the next completed task. If there is no such task at present, it will block. ExecutorService executorService = Executors.newCachedThreadPool(); CompletionService cs = new ExecutorCompletionService(executorService); for (int i = 0; i < 10; i++) { cs.submit(new Callable<String>() { @Override public String call() throws Exception { long sleepValue = (int)(Math.random() * 1000); System.out.println("sleep=" + sleepValue + " " + Thread.currentThread().getName()); Thread.sleep(sleepValue); return "Return value:" + sleepValue + " " + Thread.currentThread().getName(); } }); } for (int i = 0; i < 10; i++) { System.out.println(cs.take().get()); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
From the running results, the method take() obtains the Future object in the order of fast to slow task execution speed, because the printing time is from small to large.
sleep=738 pool-1-thread-1 sleep=911 pool-1-thread-8 sleep=467 pool-1-thread-10 sleep=407 pool-1-thread-7 sleep=131 pool-1-thread-3 sleep=79 pool-1-thread-6 sleep=563 pool-1-thread-4 sleep=869 pool-1-thread-5 sleep=545 pool-1-thread-2 sleep=551 pool-1-thread-9 Return value: 79 pool-1-thread-6 Return value: 131 pool-1-thread-3 Return value: 407 pool-1-thread-7 Return value: 467 pool-1-thread-10 Return value: 545 pool-1-thread-2 Return value: 551 pool-1-thread-9 Return value: 563 pool-1-thread-4 Return value: 738 pool-1-thread-1 Return value: 869 pool-1-thread-5 Return value: 911 pool-1-thread-8
poll() method
The function of the method poll() is to get and remove the Future that represents the next completed task. If such a task does not exist, null will be returned, and the method pol() is unimpeded
Plug effect:
public class TestDemo2 { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); CompletionService cs = new ExecutorCompletionService(executorService); for (int i = 0; i < 1; i++) { cs.submit(new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(3000); System.out.println("3 Seconds later"); return "Return value"; } }); } for (int i = 0; i < 1; i++) { System.out.println(cs.poll()); } } }
The poll() method returns null because there is currently no Future object for any completed task, so it returns null. The poll() method does not have blocking properties.
poll(long timeout, TimeUnit unit)
The function of the method Future pol(long timeout, TimeUnit unit) is to wait for the specified timeout time. When the value is obtained within the timeout time, it will continue to execute downward immediately. If the timeout occurs, it will also execute downward immediately.
public class TestDemo3 { public static void main(String[] args) { try { MyCallableA a = new MyCallableA(); MyCallableB b = new MyCallableB(); Executor executor = Executors.newSingleThreadExecutor(); CompletionService cs = new ExecutorCompletionService(executor); cs.submit(a); cs.submit(b); for (int i = 0; i < 2; i++) { System.out.println("zzzzzzzzzzz" + " " + cs.take()); } System.out.println("main end"); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyCallableA implements Callable<String> { @Override public String call() throws Exception { System.out.println("MyCallableA begin " + System.currentTimeMillis()); Thread.sleep(1000); System.out.println("MyCallableA end " + System.currentTimeMillis()); return "returnA"; } } class MyCallableB implements Callable<String> { @Override public String call() throws Exception { System.out.println("MyCallableB begin " + System.currentTimeMillis()); Thread.sleep(5000); int i = 0; if (i == 0) { throw new Exception("Throw an exception!"); } System.out.println("MyCallableB end " + System.currentTimeMillis()); return "returnB"; } }
Although MyCallableB has an exception, it does not call FutureTask's get() method, so there is no exception.
Call get() method:
Execution sequence of exchange A and B:
Task B is abnormal, and task A is not output.
Call the poll() method:
public class TestDemo3 { public static void main(String[] args) { try { MyCallableA a = new MyCallableA(); MyCallableB b = new MyCallableB(); Executor executor = Executors.newSingleThreadExecutor(); CompletionService cs = new ExecutorCompletionService(executor); cs.submit(a); cs.submit(b); for (int i = 0; i < 2; i++) { System.out.println("zzzzzzzzzzz" + " " + cs.poll()); } Thread.sleep(6000); System.out.println("A place" + " " + cs.poll()); System.out.println("B place" + " " + cs.poll()); System.out.println("main end"); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyCallableA implements Callable<String> { @Override public String call() throws Exception { System.out.println("MyCallableA begin " + System.currentTimeMillis()); Thread.sleep(1000); System.out.println("MyCallableA end " + System.currentTimeMillis()); return "returnA"; } } class MyCallableB implements Callable<String> { @Override public String call() throws Exception { System.out.println("MyCallableB begin " + System.currentTimeMillis()); Thread.sleep(5000); int i = 0; if (i == 0) { throw new Exception("Throw an exception!"); } System.out.println("MyCallableB end " + System.currentTimeMillis()); return "returnB"; } }
The return value of poll() is null after the exception of Task B
poll() calls the get() method to get the return value:
The return value of task A is normal, and the return value of Task B is abnormal.
Change the execution sequence of tasks A and B:
Task A did not print, Task B threw an exception.
Future submit(Runnable task, V result)
public class TestDemo4 { public static void main(String[] args) { UserInfo userInfo = new UserInfo(); MyRunnable5 myRunnable5 = new MyRunnable5(userInfo); Executor executor = Executors.newCachedThreadPool(); CompletionService cs = new ExecutorCompletionService(executor); Future<UserInfo> future = cs.submit(myRunnable5, userInfo); try { System.out.println(future.get().getUsername() + " " + future.get().getPassword()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class UserInfo { private String username; private String password; public UserInfo() { super(); } public UserInfo(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } class MyRunnable5 implements Runnable { private UserInfo userInfo; public MyRunnable5(UserInfo userInfo) { this.userInfo = userInfo; } @Override public void run() { userInfo.setUsername("usernameValue"); userInfo.setPassword("passwordValue"); System.out.println("run It's running "); } }
summary
The interface CompletionService can completely avoid the disadvantage of FutureTask class blocking, and can handle the return value of Future more effectively. That is to say, if a task is executed first, the CompletionService will get the return value of the task first and then handle it.