JDK7 introduced the Fork/join framework, the so-called Fork/join framework, a personal explanation: fork decomposition tasks into separate sub-tasks, with multithreading to perform these subtasks, join merge subtasks results. This enables you to perform a task in a multi-threaded manner.
The fork/join introduced by JDK7 has three core classes:
Forkjoinpool, the thread pool that executes the task
Forkjoinworkerthread, the worker thread that performs the task
Forkjointask, a task abstract class for Forkjoinpool.
Because Forkjointask is more complex, abstract methods are more, daily use generally do not inherit forkjointask to achieve the custom task, but inherit the forkjointask of the two sub-classes:
Recursivetask: Child task with return result when used
Recursiveaction: Child tasks are used without returning results
For the principles of the Fork/join framework, Doug Lea's article:A Java fork/join Framework
After looking at many examples on the web, it is common to find the logic of implementing the Compute method in a custom task class:
if The task is small enough to directly return the result or else to split into N subtasks , calling each child task in turn, and then executing the child task by calling the join method of each child task to merge the execution results
The call to execute the custom task is Forkjoinpool's Execute method, so the first thing to look at is the Forkjoinpool execute method, to see how the task is different from the normal thread pool:
Public void Execute (forkjointask<?> Task) { ifnull) thrownew nullpointerexception (); Forkorsubmit (Task); }
So forkorsubmit is the real way to execute Forkjointask:
Private<T>voidForkorsubmit (forkjointask<t>Task) {Forkjoinworkerthread W; Thread T=Thread.CurrentThread (); if(Shutdown)Throw Newrejectedexecutionexception (); if((tinstanceofForkjoinworkerthread) &&(W= (forkjoinworkerthread) t). Pool = = This) W.pushtask (Task); Else //normal execution is called by the main thread, so focus on addsubmissionaddsubmission (Task); }
So the first thing we should focus on is the Addsubmission method, and find that what we do is similar to the normal thread pool, which is to add the task to the queue, and the other is to use unsafe to manipulate the memory for adding the Task object.
Private voidAddsubmission (forkjointask<?>t) {FinalReentrantlock lock = This. Submissionlock; Lock.lock (); Try { //The queue is just an ordinary array instead of the blockingqueue of the normal thread pool,//The work of waking up the worker thread is done by the following signalwork//using unsafe for memory operations, placing tasks in arraysForkjointask<?>[] Q;intS, m; if((q = submissionqueue)! =NULL) { LongU = (((s = queuetop) & (M = q.length-1)) << Ashift) +Abase; Unsafe.putorderedobject (q, U, t); Queuetop= s + 1; if(S-queuebase = =m)//array is full, scaling is expanded for arraysGrowsubmissionqueue (); } } finally{lock.unlock (); } //notifies you that a new task has been made: two operations, with idle threads waking the thread//Otherwise, if you can create a new worker thread, create a new worker thread for this task//if it is not possible to return, wait until there are idle threads to perform this tasksignalwork (); }
The next thing to figure out is that when you fork in the compute, the action is executed in the same thread as the main task, and Fork is executed if the task becomes multithreaded:
Public Final forkjointask<v> Fork () {( (forkjoinworkerthread) Thread.CurrentThread ()) . Pushtask ( this); return This ; }
In the above analysis Forkorsubmit also saw the forkjoinworkerthread pushtask method call, then see this method:
Final voidPushtask (forkjointask<?>t) {//The basic logic of code and the Addsubmission method of Forkjoinpool are basically consistent//is to add the task to the task queue, which is added to the Forkjoinworkerthread//built-in task queueForkjointask<?>[] Q;intS, m; if((q = queue)! =NULL) {//Ignore if queue removed LongU = (((s = queuetop) & (M = q.length-1)) << Ashift) +Abase; Unsafe.putorderedobject (q, U, t); Queuetop= s + 1;//or use Putorderedint//It's not quite clear . if((S-= queuebase) <= 2) pool.signalwork (); Else if(s = =m) growqueue (); } }
See here all of a sudden into the deadlock, why Forkjoinworkerthread to build a queue, and if the sub-task is still in the same line range, how to implement concurrent sub-task? The next article continues.
Java.util.concurrent package Source Reading Fork/join The first experience of the framework