Multithreading (v)

Source: Internet
Author: User

InvokeAll said, we look at the Abstractexecutorservice Invokeany method, the method before the code explained, and InvokeAll is different, in a given task, if a task is completed (no exception thrown), Returns the result of the task execution. This can be seen from the return value of the method. Does not require all tasks to complete, as long as a complete (no exception) can be. Description of the JDK:

<T> T Invokeany ( Collection <? extends Callable<T>> tasks)
Executes the given task, and returns the result if a task has completed successfully (that is, an exception is thrown).

The return value of T also illustrates this point.

Source:

 Public<T> T invokeany (collection<?extendsCallable<t>>tasks)throwsinterruptedexception, executionexception {Try {            returnDoinvokeany (Tasks,false, 0); } Catch(TimeoutException cannothappen) {assert false; return NULL; }    }     Public<T> T invokeany (collection<?extendsCallable<t>>Tasks,LongTimeout, timeunit unit)throwsinterruptedexception, Executionexception, timeoutexception {returnDoinvokeany (Tasks,true, Unit.tonanos (timeout)); }

This code has nothing to say, the key point lies in the Doinvokeany () method above, directly on the source:

Private<T> T doinvokeany (collection<?extendsCallable<t>>Tasks,BooleanTimedLongNanos)throwsinterruptedexception, Executionexception, timeoutexception {if(Tasks = =NULL)            Throw NewNullPointerException (); intNtasks =tasks.size (); if(Ntasks = = 0)            Throw Newillegalargumentexception (); List<Future<T>> futures=NewArraylist<future<t>>(Ntasks); Executorcompletionservice<T> ECS =NewExecutorcompletionservice<t> ( This); //for efficiency, especially in executors with limited//parallelism, check to see if previously submitted tasks is//Done before submitting more of them. This interleaving//plus the exception Mechanics account for messiness of main//Loop.        Try {            //Record Exceptions So, if we fail to obtain any//result, we can throw the last exception we got.Executionexception EE =NULL; LongLasttime = timed? System.nanotime (): 0; Iterator<?extendsCallable<t>> it =Tasks.iterator (); //Start one task for sure; the rest incrementallyFutures.add (Ecs.submit (It.next ())); --Ntasks; intActive = 1;  for (;;) { Future<T> f =Ecs.poll (); if(f = =NULL) {                    if(Ntasks > 0) {                        --Ntasks;                        Futures.add (Ecs.submit (It.next ())); ++active; }                    Else if(Active = = 0)                         Break; Else if(timed) {f=Ecs.poll (Nanos, timeunit.nanoseconds); if(f = =NULL)                            Throw Newtimeoutexception (); Longnow =System.nanotime (); Nanos-= Now-Lasttime; Lasttime=Now ; }                    ElseF=Ecs.take (); }                if(F! =NULL) {                    --active; Try {                        returnF.get (); } Catch(executionexception EEx) {ee=EEx; } Catch(RuntimeException Rex) {EE=NewExecutionexception (Rex); }                }            }            if(EE = =NULL) EE=Newexecutionexception (); Throwee; } finally {             for(future<t>f:futures) F.cancel (true); }    }

The complexity of this comparison is a step-by-step:

The first is to create a return value based on the task.

list<future<t>> futures= New arraylist<future<t>> (ntasks);

Ntasks is the current number of tasks.

Then there is the description of the Executorcompletionservice JDK that is created for this class:

Use the provided Executor to perform the completionservice of the task. This class arranges the tasks that are submitted when they are completed, placing them on a queue that can be accessed using take. This class is very lightweight and is suitable for temporary use when performing several sets of tasks. The specific source code, which we will analyze later.

The specific implementation of the code in Try/catch

Ntasks Current number of tasks

Number of processes currently running by active

Start one task for sure; The rest incrementally

Futures.add (Ecs.submit (It.next ()));

A task is submitted first, and then into a loop, so that efficiency can be submitted.

Then enter the infinite loop, which is divided into two situations:

if (f = = null)

And we'll start by talking about the role of the Ecs.poll method: retrieving and removing the future that represents the next completed task, or nullif no such task exists.

if f = = NULL indicates that there are no tasks to complete, there are three cases:

(1) The current process has not been submitted, then continue to submit the process (the later the slower, so in the time of submission of the task is usually the short execution time of the task ahead, that is, from the small order, to be able to submit efficiency)

(2) If the number of processes currently executing is 0, a direct jump out of the loop, this is an abnormal branch, after jumping out of the loop, the execution is:if (ee = = null) EE = new executionexception (); throw ee; Throws an exception.

(3) If there is no task to submit, and there is a task in the execution, that is (1)/(2) is not established, immediately to get the results of the task, if there is a time limit, then F = Ecs.poll (Nanos, Timeunit. Nanoseconds);, gets the time-out exception that is thrown. No, it is f.get ();

The conditions (3) are described here, if there is no task to submit, and there is currently a task to execute only in the case of execution to (3), this is also to be able to get more quickly results, as soon as possible to get the task first to complete which task. This can block the result of getting the task.

If (f! = null)

F is not NULL to indicate that a task has been completed, reduce the number of tasks being performed, and get the execution result directly (possibly blocking).

Finally, in finally, all tasks are canceled.

InvokeAll's main logic has been analyzed, we also left a small tail, how he can ensure that the task after the execution of the direct plug into the sequence of results, this comparison is important, is the poll method.

First, let's take a look but call the build function source code:

 PublicExecutorcompletionservice (Executor Executor, Blockingqueue<Future<V>>completionqueue) {        if(Executor = =NULL|| Completionqueue = =NULL)            Throw NewNullPointerException ();  This. Executor =executor;  This. AES = (ExecutorinstanceofAbstractexecutorservice)?(abstractexecutorservice) Executor:NULL;  This. Completionqueue =Completionqueue; }

From the built function, this executor is abstractexecutorservice. The main methods we use are:

Ecs.submit (It.next ())

Ecs.poll ();

Ecs.poll (Nanos, Timeunit. Nanoseconds);

The main key to seeing these methods is that the result queue completionqueue, either take or poll, is blockingqueue supported, from the source code in the method poll () and take () to see. The source code above is:

 PublicFuture<v>Submit (Runnable task, V result) {if(Task = =NULL)Throw NewNullPointerException (); Runnablefuture<V> f =newtaskfor (task, result); Executor.execute (Newqueueingfuture (f)); returnF; }     PublicFuture<v> Take ()throwsinterruptedexception {returnCompletionqueue.take (); }     PublicFuture<v>poll () {returnCompletionqueue.poll (); }

Then there is one main question: How do you put the task into this queue? So first of all we need to focus on the method of submitting the task:

 Public Future<v> Submit (Runnable task, V result) {        ifnullthrowNew nullpointerexception ();        Runnablefuture<V> f = newtaskfor (task, result);        Executor.execute (new  queueingfuture (f));         return f;    }

Queueingfuture for internal class, the source code is:

Private class extends Futuretask<void> {        queueingfuture (runnablefuture<V> Task) {            super NULL );             this. Task = task;        }         protected void Done () {completionqueue.add (Task);}         Private Final future<v> task;    }

See the redefinition of this method:protected void done () {Completionqueue.add (Task);}

About the method of interface done () JDK Description:

protected void done ()

The protected method is called when this task transitions to the state isDone (whether normal or canceled). The default implementation does not perform any action. Subclasses can override this method to invoke completion callbacks or to perform bookkeeping. Note that you can query the state within the implementation of this method to determine whether the task has been canceled.

The subclass Queueingfuture overrides the Done () method, and when the task is completed, the result of the execution is put into completionqueue. Implement the above mentioned when the task is completed, it is placed in the completed blocking queue.

For this reason, there are two applications for Executorcompletionservice in the JDK:

Suppose you have a set of solvers for a problem, each solver can return some type of result value, and you want to run them at the same time, using the method use (result R) to handle the return result of each solver that returns a non-null value. You can write a program like this:

voidSolve (Executor E, collection<callable<result>>solvers)throwsinterruptedexception, executionexception {completionservice<Result> ECS =NewExecutorcompletionservice<result>(e);  for(callable<result>s:solvers) Ecs.submit (s); intn =solvers.size ();  for(inti = 0; I < n; ++i) {Result R=Ecs.take (). get (); if(r! =NULL) use (r); }

Assume that you want to use the first non-null result in a task set, ignoring any task that encounters an exception, and cancel all other tasks when the first task is ready:

voidSolve (Executor E, collection<callable<result>>solvers)throwsinterruptedexception {completionservice<Result> ECS =NewExecutorcompletionservice<result>(e); intn =solvers.size (); List<Future<Result>> futures =NewArraylist<future<result>>(n); Result result=NULL; Try {             for(callable<result>s:solvers) Futures.add (Ecs.submit (s));  for(inti = 0; I < n; ++i) {Try{Result R=Ecs.take (). get (); if(r! =NULL) {result=R;  Break; }                } Catch(Executionexception ignore) {}}} finally {             for(future<result>f:futures) F.cancel (true); }        if(Result! =NULL) use (result); }

The second case in the JDK description and the Invokeany comparison can be analogous.

Multithreading (v)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.