Executorservice is a core interface provided by the JDK concurrency toolkit. It is equivalent to a thread pool and provides methods for executing tasks and managing lifecycles. Most of the APIs in the executorservice interface are relatively easy to use. This article mainly introduces the features and usage of the invokeall and invokeall methods. We first provide several task classes: a time-consuming task, an exception task, and a short-term task. They will be used in the next test code.
package tasks;import java.util.concurrent.Callable;import java.util.concurrent.TimeUnit;public class SleepSecondsCallable implements Callable<String>{private String name;private int seconds;public SleepSecondsCallable(String name, int seconds){this.name = name;this.seconds = seconds;}public String call() throws Exception{System.out.println(name + ",begin to execute");try{TimeUnit.SECONDS.sleep(seconds);} catch (InterruptedException e){System.out.println(name + " was disturbed during sleeping.");e.printStackTrace();return name + "_SleepSecondsCallable_failed";}System.out.println(name + ",success to execute");return name + "_SleepSecondsCallable_succes";}}
This is a time-consuming task simulated by sleep. It is a task that can be interrupted or terminated and can respond to the interrupt request.
package tasks;import java.util.concurrent.Callable;public class ExceptionCallable implements Callable<String>{private String name = null;public ExceptionCallable(){}public ExceptionCallable(String name){this.name = name;}@Overridepublic String call() throws Exception{System.out.println("begin to ExceptionCallable.");System.out.println(name.length());System.out.println("end to ExceptionCallable.");return name;}}
This is a task that may throw a null pointer exception during execution.
package tasks;import java.util.Random;import java.util.concurrent.Callable;public class RandomTenCharsTask implements Callable<String>{@Overridepublic String call() throws Exception{System.out.println("RandomTenCharsTask begin to execute...");StringBuffer content = new StringBuffer();String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();for (int i = 0; i < 10; i++){int number = random.nextInt(base.length());content.append(base.charAt(number));}System.out.println("RandomTenCharsTask complete.result=" + content);return content.toString();}}
This is a normal short-term task that generates a string consisting of 10 random characters.
1. Test invokeany (). In the first case, submit two time-consuming tasks to the thread pool: sleepsecondscallable.
/*** If one of the submitted tasks is successfully completed (no exception is thrown), other unfinished tasks will be terminated */public static void invokeany1 () throws exception {executorservice = executors. newfixedthreadpool (3); List <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New sleepsecondscallable ("T1", 2); tasks. add (New sleepsecondscallable ("T2", 1); string result = executorservice. invokeany (tasks); system. out. println ("result =" + result); executorservice. shutdown ();}
The execution result of the program is: return the execution result of the T2 thread t2_sleepsecondscallable_succes, and T1 throws java. Lang. interruptedexception: sleep interrupted. That is to say:
Once one task is completed normally (no exception is thrown during execution), the thread pool terminates other unfinished tasks..
In the second case, submit three exception tasks to the thread pool: predictioncallable
/*** If no task is successfully completed, the invokeany () method throws executionexception, encapsulating the exception of elements in the task **/public static void invokeany2 () throws exception {executorservice = executors. newfixedthreadpool (3); List <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); string result = executorservice. invokeany (tasks); system. out. println ("result =" + result); executorservice. shutdown ();}
The program execution result is: Java. util. Concurrent. executionexception: Java. Lang. nullpointerexception is returned when invokeany () is called. That is to say:
If no task is successfully completed in the submitted task list, an exception is thrown when invokeany is called. It does not matter which task is thrown..
Case 3: Submit 3 abnormal tasks and 1 normal time-consuming task
/*** If an exception occurs and a normal task exists, invokeany () will not throw an exception and return the first normal task */public static void invokeany3 () throws exception {executorservice = executors. newfixedthreadpool (3); List <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); tasks. add (New sleepsecondscallable ("T1", 2); string result = executorservice. invokeany (tasks); system. out. println ("result =" + result); executorservice. shutdown ();}
The program execution result is: no exception is thrown, and the result returned by the T2 task is printed. That is to say:
Invokeany () has nothing to do with the task submission order, but returns the first task completed normally..
In the fourth case, the limited version of invokeany () is used for testing. The main functions are not much different from those of the unlimited version.
/*** The tasks have been completed abnormally before the time-out, and executionexception is thrown. <br> * if the time-out period is full, no tasks have been completed yet, throw timeoutexception */public static void invokeanytimeout () throws exception {executorservice = executors. newfixedthreadpool (3); List <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); tasks. add (New exceptioncallable (); string result = executorservice. invokeany (tasks, 2, timeunit. seconds); system. out. println ("result =" + result); executorservice. shutdown ();}
The execution result of the program is: executionexception. This is actually reasonable and understandable. If all the tasks are terminated abnormally before the timeout, there is no need to wait. If a running or waiting task still exists after the timeout, A timeoutexception will be thrown.
Finally, let's take a look at the method signature and Annotation of executorservice. invokeany In the JDK source code.
/** * Executes the given tasks, returning the result * of one that has completed successfully (i.e., without throwing * an exception), if any do. Upon normal or exceptional return, * tasks that have not completed are cancelled. * The results of this method are undefined if the given * collection is modified while this operation is in progress. * * @param tasks the collection of tasks * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting * @throws NullPointerException if tasks or any of its elements * are <tt>null</tt> * @throws IllegalArgumentException if tasks is empty * @throws ExecutionException if no task successfully completes * @throws RejectedExecutionException if tasks cannot be scheduled * for execution */ <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
Consistent with our test results, invokeany () returns the direct result of the first normal completed (without throwing exception) task. Once a task is completed normally or an exception occurs during the call, the thread pool terminates the tasks that are running or waiting for running (tasks that have not completed are canceled.
2. The invokeall () method is relatively easy to understand. It is to execute all the tasks in the task list and return the futue corresponding to each task. In other words, tasks do not affect each other. You can use future to track the execution status of each task, such as whether the task is canceled, whether it is completed normally or abnormally, this mainly uses the API provided by the future class.
Public static void testinvokeall () throws exception {executorservice = executors. newfixedthreadpool (5); List <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New sleepsecondscallable ("T1", 2); tasks. add (New sleepsecondscallable ("T2", 2); tasks. add (New randomtencharstask (); tasks. add (New exceptioncallable (); // the thread that calls this method will be blocked until all tasks are completed (normal completion/abnormal Exit) list <future <string> Results = executorservice. invokeall (tasks); // The System statement can be executed only after all tasks in the task list are completed. out. println ("wait for the result. "+ results. size (); executorservice. shutdown (); For (Future <string> F: Results) {// iscanceled = false, isdone = truesystem. out. println ("iscanceled =" + F. iscancelled () + ", isdone =" + F. isdone (); // The executionexceptioncallable task reports executionexceptionsystem. out. println ("task result =" + F. get ());}}
The execution results and conclusions of the program have been directly written in the code comment. Invokeall is a blocking method that waits for all tasks in the task list to be completed. Future. isdone () always returns true, whether the task is completed normally or aborted abnormally. You can use future. iscanceled () to determine whether the task is canceled during execution. You can use future. Get () to obtain the returned results of a task, or an exception thrown during task execution.
In the second case, test the limited version of invokeall (collection <? Extends callable <t> tasks, long timeout, timeunit Unit)
/*** You can use future. iscanceled () determines whether the task is canceled or completed (normal/abnormal) <br> * future. isdone () always returns true. For invokeall () callers, */public static void testinvokealltimeout () throws exception {executorservice = executors. newfixedthreadpool (5); List <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New sleepsecondscallable ("T1", 2); tasks. add (New sleepsecondscallable ("T2", 2); tasks. add (New sleepsecondscallable ("T3", 3); tasks. add (New randomtencharstask (); List <future <string> Results = executorservice. invokeall (tasks, 1, timeunit. seconds); system. out. println ("wait for the result. "+ results. size (); For (Future <string> F: Results) {system. out. println ("iscanceled =" + F. iscancelled () + ", isdone =" + F. isdone ();} executorservice. shutdown ();}
The execution result is:
Wait for the result.4
Iscanceled = true, isdone = true
Iscanceled = true, isdone = true
Iscanceled = true, isdone = true
Iscanceled = false, isdone = true
That is to say, the task that has not been completed will be canceled, that is, the future. iscancelled () returns true; whether the task is completed normally or aborted abnormally before the superperiod, future. iscancelled () returns false.
In the third case, the thread is interrupted until the invokeall execution is complete.
/*** If the thread is interrupted when it is waiting for the invokeall () execution to complete, interruptedexception will be thrown. <br> * at this time, the thread pool will terminate the unfinished task, this is mainly to reduce the waste of resources. */public static void testinvokeallwheninterrupt () throws exception {final executorservice = executors. newfixedthreadpool (5); // call the invokeall thread invokeallthread = new thread () {@ overridepublic void run () {list <callable <string> tasks = new arraylist <callable <string> (); tasks. add (New sleepsecondscallable ("T1", 2); tasks. add (New sleepsecondscallable ("T2", 2); tasks. add (New randomtencharstask (); // The call thread will be blocked until all tasks are executed (normal completion/abnormal exit) Try {list <future <string> Results = executorservice. invokeall (tasks); system. out. println ("wait for the result. "+ results. size ();} catch (interruptedexception e) {system. out. println ("I was wait, but my thread was interrupted. "); E. printstacktrace () ;}}; invokeallthread. start (); thread. sleep (200); invokeallthread. interrupt (); executorservice. shutdown ();}
The invokeallthread thread calls executorservice. invokeall (). When the task execution is completed, the invokeallthread is interrupted by other threads. At this time,
Executorservice. invokeall () will throw java. Lang. interruptedexception, and the task t1 and t2 will be terminated and throw java. Lang. interruptedexception: sleep interrupted.
That is to say, once an exception occurs in the executorservice. invokeall () method, tasks not completed in the thread pool will be canceled.