Callable and futureThe Executor framework divides the unit of work into tasks, that is, the task is a logical unit of work, and the thread is the mechanism by which the task executes asynchronously. Runnable is an abstraction of the task, and the task is performed independently in an ideal state, but the runnable run () cannot return a result or throw a checked exception, which is inconsistent with some of our actual tasks. In the execution of runnable tasks through threads or executor, it is not only impossible to return the results of a task, sometimes we want to control a task, or cancel or terminate it, but once the task is submitted in executor, it is difficult to control the life cycle of the task in a single Although Executorservice extends the executor interface, it adds life-cycle control, but based on the thread pool, there is no single control over a task that is for all tasks. The JDK also provides another better task abstract callable, which is very similar to runnable, but there are some differences. The callable task can return an execution result, but when we submit a callable task to executor, we get a future object, which is like this callable an invoice receipt submitted to executor, using this receipt, In the future we can get the results of the execution of the task, or when we want to cancel the task, we can also take advantage of this task submitted by the future object to cancel the task, and we can also use it to get the status of the task at any time after the commit (whether it is canceled, whether it is completed).
similarities and differences between callable and runnable:
- The method defined by callable is call (), and the method defined by Runnable is run ().
- The callable call method can have a return value, and the runnable run method cannot have a return value.
- The callable call method can throw a checked exception, and the runnable run method cannot throw an exception.
There are tools in the tool class executors to turn the runnable task into callable. You can use executor to perform a callable task, or you can turn callable into a Futuretask object and then go to the thread to execute it.
The future is the result of an asynchronous computation that describes the life cycle of the task and provides a way to get the results of the task execution, cancel the task, and check whether the task has been completed or canceled.
There are several ways to create a future. All the submit methods in Executorservice will return a future, using the returned future you can get the result of the task execution, or cancel the task. You can display the runnable or callable instantiation of a futuretask.
The following example shows some methods of callable and future, the program defines two tasks C1 and C2, and the execution time of the simulation C2 is about 8 seconds, then calls the future related methods in turn
Import Java.util.random;import Java.util.concurrent.callable;import java.util.concurrent.CancellationException; Import Java.util.concurrent.executionexception;import Java.util.concurrent.executorservice;import Java.util.concurrent.executors;import Java.util.concurrent.future;public class Callableandfuture {public static void Main (string[] args) {Executorservice es = Executors.newfixedthreadpool (5); callable<integer> C1 = new Target (false); callable<integer> C2 = new Target (true); Future<integer> F1 = es.submit (c1); future<integer> F2 = es.submit (c2); int res = 0;try {res = F1.get ();} catch (Interruptedexception e) {//TODO Auto-ge Nerated catch Blocke.printstacktrace ();} catch (Executionexception e) {//TODO auto-generated catch Blocke.printstacktrace ();} Boolean iscancelled = F1.iscancelled (); Boolean isDone = F1.isdone (); System.out.println (RES); System.out.println (iscancelled); System.out.println (IsDone); System.out.println ("---------------------------"); try {Boolean cancEl = F2.cancel (true); int res2 = F2.get (); iscancelled = f1.iscancelled (); isDone = F1.isdone (); System.out.println (Res2); System.out.println (cancel); System.out.println (iscancelled); System.out.println (IsDone);} catch (Cancellationexception e) {//TODO auto-generated catch BlockSystem.out.println ("task canceled.");} catch ( Interruptedexception e) {//TODO auto-generated catch BlockSystem.out.println ("The task is interrupted.")} catch (Executionexception e) { TODO auto-generated Catch blockSystem.out.println ("Task execution exception.");}} Class Target implements Callable<integer> {private Boolean sleep = False;public Target (Boolean sleep) {//TODO auto- Generated constructor stubthis.sleep = sleep;} @Overridepublic Integer Call () throws Exception {//TODO auto-generated method stubif (Sleep) {thread.sleep (8000);} int i = new Random (). Nextint (+); return i;}}
Execution results of the task:
982falsetrue---------------------------task was canceled.
Related methods of the future interface
The Cancel () method can attempt to cancel the execution of a task, if the current task has completed, or has been canceled, or cannot be canceled for some reason, the undo operation fails, returns FALSE, and if the task is not already running, calling the Cancel () method will cause the task to never run If the task is already running when the Cancel () method is called, the value of the parameter Boolean, if true, means that the execution of the task is interrupted immediately, otherwise, after the end of the task waiting for the run, an attempt is made to cancel and return false.
Iscancel () returns True if it is canceled before the task is completed properly, otherwise, false is returned.
IsDone (), returns True if the task has completed, and returns true due to a normal termination, exception, or cancellation.
Get (), if the task is completed, then get will return or throw a exception immediately, and if the task is not completed, get will block until it is complete. If the task throws an exception, get encapsulates the exception as Executionexception and then re-throws it, and if the task is canceled, get throws cancellationexception.
Futuretask
The Futuretask class is equivalent to implementing both the runnable and the future interfaces, providing a concrete implementation of the future interface that can be used to package callable or runnable tasks using Futuretask. Because Futuretask implements the Runnable interface, it can be handed to executor for execution, or directly to run ().
An example of using Futuretask
Import Java.util.random;import Java.util.concurrent.callable;import Java.util.concurrent.executor;import Java.util.concurrent.executors;import Java.util.concurrent.futuretask;public class MyFutureTask {public static void Main (string[] args) throws Exception {Executor Executor = Executors.newfixedthreadpool (5); callable<integer> callable = new Mytarget (); futuretask<integer> ft = new futuretask<> (callable); Executor.execute (ft); System.out.println (Ft.get ());//Direct call to Run//ft.run ();//system.out.println (Ft.get ()); System.out.println ("-----------------------"); Runnable Runnable = new Myrunnabletarget (); futuretask<string> ft2 = new futuretask<string> (runnable, "SUCCESS"); Executor.execute (ft2); System.out.println (Ft2.get ());}} Class Mytarget implements callable<integer> {@Overridepublic Integer call () throws Exception {//TODO auto-generate D method Stubint i = new Random (). Nextint (+); return i;}} Class Myrunnabletarget implements Runnable {@Overridepublic void run () {//TODO auto-generated method StubSystem.out.println ("Runnable is invoke ...");}}
Program output:
280-----------------------Runnable is invoke ... SUCCESS
Completionservice
Sometimes we need to use executor to perform a batch of tasks, each task has a return value, use the future to solve this problem, we need to save the future of each task submitted, and then call the Get method polling, to get the results of the completed task, Such a process is uninteresting. We hope that once a batch of tasks is submitted, the executor execution end is returned to us as a completed future collection.
Completionservice integrates the functions of executor and blockingqueue. You can hand over a batch of callable tasks to it and then use the take and poll methods similar to the one in the queue to get this result when the results are complete, like a packaged future. A service that separates the production of new asynchronous tasks from the results of using the completed tasks. The task that the producer Submit method performs. The consumer take the completed tasks and process their results in the order in which they were completed. The Executorcompletionservice class is an implementation class that implements the Completionservice interface, which gives the calculation task to an incoming executor to execute.
Here is an example of a executorcompletionservice
Import Java.util.random;import Java.util.concurrent.callable;import Java.util.concurrent.executor;import Java.util.concurrent.executorcompletionservice;import Java.util.concurrent.executors;public Class Testcompletionservice {Private class Target implements Callable<integer> {@Overridepublic Integer call () throws Exception {//TODO auto-generated method Stubint i = new Random (). Nextint (+); return i;}} public static void Main (string[] args) throws Exception {Executor Executor = Executors.newfixedthreadpool (5); executorcompletionservice<integer> ECS = new executorcompletionservice<> (executor); callable<integer> C1 = new Testcompletionservice (). New Target (); callable<integer> C2 = new Testcompletionservice (). New Target (); callable<integer> C3 = New Testcompletionservice (). New Target (); Ecs.submit (C1); Ecs.submit (C2); Ecs.submit (C3); System.out.println (Ecs.take (). get ()); System.out.println (Ecs.poll (). get ()); System.out.println (Ecs.take (). get ());}}
This separates the future and the future of the completed task is added to the Blockingqueue for direct access by the user.
Regarding the difference between the poll method and the Get method, the poll method is non-blocking, there is a return, and none of the Null,take methods are blocked, and no words will wait.
time frame for batch processing and task execution
In some scenarios, we need to work on multiple tasks at the same time and get results, and using the above Completionservice to separate the completed tasks from the unfinished tasks seems to work, but if one of these tasks is time-consuming, it will affect the completion speed of the entire batch task. For example, in a page, we need to get data from multiple data sources, and on the page display, and we want the entire page loading process not more than 2 seconds, then those more than 2 seconds did not respond successfully data source data is replaced with the default value, Executorservice provides InvokeAll () To complete the task.
Below we demonstrate the InvokeAll method through an example, the program defines 3 tasks, C1, C2, C3 simulation Execution time is 1, 2, 3 seconds, the program allows the maximum execution time is 2 seconds, more than 2 seconds of the task will be canceled.
Import Java.util.arraylist;import java.util.iterator;import Java.util.list;import Java.util.random;import Java.util.concurrent.callable;import Java.util.concurrent.cancellationexception;import Java.util.concurrent.executionexception;import Java.util.concurrent.executorservice;import Java.util.concurrent.executors;import Java.util.concurrent.future;import Java.util.concurrent.timeunit;public Class Testcompletionservice {Private class Target implements callable<integer> {private int a = 0;public Target (int A) {//TODO auto-generated constructor stubthis.a = A;} @Overridepublic Integer Call () throws Exception {//TODO auto-generated method Stubthread.sleep (1000*a); return A;}} public static void Main (string[] args) {Executorservice es = Executors.newfixedthreadpool (5); callable<integer> C1 = new Testcompletionservice (). New Target (1); callable<integer> C2 = new Testcompletionservice (). New Target (2); callable<integer> C3 = New Testcompletionservice (). New Target (3); list<callable<integer>> list = new arraylist<> (); List.add (C1); List.add (C2); List.add (C3); try {list< future<integer>> res = Es.invokeall (list, 2, timeunit.seconds);iterator<future<integer>> it = Res.iterator (); while (It.hasnext ()) {future<integer> f = it.next (); int i = F.get (); System.out.println (i);}} catch (Cancellationexception e) {System.out.println ("task Cancel"),} catch (Interruptedexception e) {System.out.println (" Interrupt exception ");} catch (Executionexception e) {System.out.println ("execute exception");}}}
Output of the program:
12 Task Cancellation
It is important to note that all of the time-related methods in java.util.concurrent treat negative numbers as 0 and do not require additional processing
Java Concurrency--callable and future