Using multithreading technology to allow different tasks to run in different threads can improve CPU utilization. But just by task, the granularity is still a little large. The effect of using multithreading concurrency is not obvious when some tasks in the task are running at a much larger time than other tasks. In this case, the long task is divided into a small time-consuming task, can effectively alleviate the bottleneck of concurrency, and ultimately the results of small tasks merged to obtain the results of the complete task. Fork/join can be a good way to achieve this task of dividing the final merge of ideas (you can consider it as a concurrent version of the partition).
First, Forkjointask & Forkjoinpool
1. forkjointask<v>
Extended from future, it represents a more lightweight, fine-grained concurrency unit than a task. It is an abstract class in itself, with two important abstract subclasses: Recursiveaction and Recursivetask<v>, which can be defined by overriding their compute methods, noting that the compute of the former is not with the return value, And the latter one has the return value.
The A. Fork () method allows the Forkjointask task to execute asynchronously and also allows a new forkjointask to be started from the existing forkjointask. Variant: Invoke (), InvokeAll ()
B. Conversely, the join () method allows one forkjointask to wait for another forkjointask execution to complete. Variant: Get ()
2. Forkjoinpool
Inherited from Abstractexecutorservice, used for scheduling forkjointask.
3. Scheduling mechanism
A master's Forkjointask is submitted to Forkjoinpool and executed. Then Forkjointask starts (by fork (), and so on) to start its subtasks and wait for them to complete (by means of get (), etc.).
Ii. use of the Fork/join framework
The following is the most classic Fork/join framework usage scenario:
If task is small enough
Execute the Task
Else
Divide it into several smaller tasks
Invoke All Tasks
Group results
Example:
Import java.util.concurrent.ExecutionException;
Import Java.util.concurrent.ForkJoinPool;
Import Java.util.concurrent.RecursiveTask;
Import Java.util.concurrent.TimeUnit;
public class Fjcount extends Recursivetask {private String document[];
private int start, end;
Private String word;
Fjcount (string _d[], int _s, int _e, String _w) {document = _d;
start = _s;
end = _e;
Word = _w;
@Override protected Object Compute () {int result = 0;
if (End-start <) {result = count (document, start, end, word);
else {int mid = (start + end)/2;
Fjcount Task1 = new Fjcount (document, Start, Mid, Word);
Fjcount task2 = new Fjcount (document, mid+1, end, word);
InvokeAll (Task1, Task2);
try {result = (int) task1.get () + (int) task2.get (); catch (Interruptedexception |
Executionexception e) {e.printstacktrace ();
} return result;
int count (string []document, int start, int end, String word) {int counter = 0; For (int i = start; I <= end; ++i) {if (document[i] = word) {++counter;
} return counter;
public static void Main (String ... arg) {string document[] = new STRING[100];
for (int i = 0; i < ++i) {if (i%10 = = 0) document[i] = "Test";
else document[i] = "";
Fjcount test = new Fjcount (document, 0,, "test");
Forkjoinpool pool = new Forkjoinpool ();
Pool.execute (test);
do {System.out.println ("****************************");
System.out.printf ("Main:paralleism:%d\n", pool.getparallelism ());
System.out.printf ("Main:active Threads:%d\n", Pool.getactivethreadcount ());
System.out.printf ("Main:task Count:%d\n", Pool.getqueuedtaskcount ());
System.out.printf ("Main:steal Count:%d\n", Pool.getstealcount ());
try {TimeUnit.SECONDS.sleep (1);
}catch (interruptedexception e) {e.printstacktrace ();
} while (!test.isdone ());
Pool.shutdown (); try {pool.awaittermination (1, Timeunit.days);
}catch (interruptedexception e) {e.printstacktrace ();
try {System.out.printf ("main:the word appears%d times in the document", Test.get ()); catch (Interruptedexception |
Executionexception e) {e.printstacktrace (); }
}
}
Third, work theft
Forkjoinpool maintains a list of tasks for each thread, and when a task is complete, it can rearrange the tasks that hang on the full load thread to the idle thread. It is like two of people move bricks, first moved back to help the other person to carry the remaining bricks. This is called job theft, which solves the scheduling problem between tasks of different sizes. The job theft feature is one of the differences between Forkjoinpool and some other executorservice.
Iv. Summary
Fork/join by dividing tasks into finer-grained units, the bottleneck can be effectively reduced and CPU usage is increased. Consider using fork/join when problems can be divided into a number of sub problems that can be handled in parallel. For example, the Parallelsort method of arrays is achieved by Fork/join.
Reference:
Http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
Http://www.oracle.com/technetwork/articles/java/fork-join-422606.html
Http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinTask.html
Http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinPool.html
"Java 7 Concurrency Cookbook"
The well-grounded Java Developer