Fork/join Tasks for Java

Source: Internet
Author: User

When we need to do a lot of small tasks, experienced Java developers will use line pool to perform these small tasks efficiently. However, there is a task, for example, to sort an array of more than 10 million elements, which itself can be executed concurrently, but how to disassemble it into a small task needs to be split dynamically during the execution of a task. In this way, large tasks can be broken down into small tasks, small tasks can continue to be broken down into smaller tasks, and finally the results of the task summary consolidation, to obtain the final result, this model is the Fork/join model.

Java7 introduced the Fork/join framework, and we can easily implement Fork/join mode by Recursivetask this class.

For example, a recursivetask that sums a large array in parallel can be written like this:

1  Public classSumtaskextendsRecursivetask<long> {2     Static Final intTHRESHOLD = 100;3     Long[] array;4     intstart;5     intend;6 7Sumtask (Long[] Array,intStartintend) {8          This. Array =Array;9          This. Start =start;Ten          This. end =end; One     } A  - @Override -     protectedLong Compute () { the         if(End-start <=THRESHOLD) { -             //If the task is small enough, calculate directly: -             Longsum = 0; -              for(inti = start; I < end; i++) { +Sum + =Array[i]; -             } +             Try { AThread.Sleep (1000); at}Catch(interruptedexception e) { -             } -System.out.println (String.Format ("Compute%d~%d =%d", start, end, sum)); -             returnsum; -         } -         //the task is too large to split in Split: in         intMiddle = (end + start)/2; -System.out.println (String.Format ("Split%d~%d ==>%d~%d,%d~%d", start, end, start, middle, middle, end)); toSumtask Subtask1 =NewSumtask ( This. Array, start, middle); +Sumtask Subtask2 =NewSumtask ( This. Array, middle, end); - InvokeAll (Subtask1, subtask2); theLong SUBRESULT1 =Subtask1.join (); *Long SUBRESULT2 =Subtask2.join (); $Long result = Subresult1 +subresult2;Panax NotoginsengSYSTEM.OUT.PRINTLN ("result =" + SUBRESULT1 + "+" + subresult2 + "==>" +result); -         returnresult; the     } +  A      Public Static voidMain (string[] args) { the         //create an array of random numbers: +         Long[] Array =New Long[400]; - fillrandom (array); $         //fork/join Task: $Forkjoinpool FJP =NewForkjoinpool (4);//Maximum number of concurrent 4 -forkjointask<long> task =NewSumtask (Array, 0, array.length); -         LongStartTime =System.currenttimemillis (); theLong result =Fjp.invoke (Task); -         LongEndTime =System.currenttimemillis ();WuyiSystem.out.println ("Fork/join sum:" + result + "in" + (Endtime-starttime) + "Ms."); the     } -  Wu     Private Static voidFillrandom (Long[] Array) { -          for(inti=0; i<array.length; i++){ AboutRandom random =NewRandom (); $             intI1 = Random.nextint (10); -Array[i] =I1; -         } -     } A}

The key to writing this fork/join task is to compute() determine whether the task is not small enough, if it is small enough, to directly calculate and return the result (note that the 1-second delay is simulated), otherwise, the task is split to two and the two subtasks are calculated separately. Returns the sum of the results of two subtasks.

The key code in the main method is fjp.invoke(task) to commit a fork/join task to execute concurrently, and then get the result of the asynchronous execution.

We set the minimum threshold for the task is 100, when committing a 400-size task, executed on the 4-core CPU, will be divided into two, and then split into four, the execution time for each of the youngest tasks is 1 seconds, due to the concurrency of 4 subtasks executed, the entire task final execution time is about 1 seconds.

Novice in writing Fork/join task, often use search engine to find an example, and then follow the example to write out the following code:

1 protectedLong Compute () {2     if(Is the task small enough?)) {3         returnComputedirect ();4     }5     //the task is too large to split in Split:6Sumtask Subtask1 =Newsumtask (...);7Sumtask Subtask2 =Newsumtask (...);8     //Call Fork () separately for the child task:9 subtask1.fork ();Ten subtask2.fork (); One     //Merge Results: ALong SUBRESULT1 =Subtask1.join (); -Long SUBRESULT2 =Subtask2.join (); -     returnSUBRESULT1 +subresult2; the}

Unfortunately, this is wrong! Miss! Of This writing does not correctly understand the task execution logic of the Fork/join model.

The size of the working thread pool used by the JDK to perform fork/join tasks equals the number of CPU cores. On a 4-core CPU, you can perform up to 4 subtasks at a time. Sum the array of 400 elements and the execution time should be 1 seconds. However, with the above code, the execution time is two seconds.

This is because the compute() thread that executes the method is itself a worker thread, and when called on two subtasks, fork() the worker thread assigns the task to another two workers, but it stops and waits for no work! This wastes a worker thread in the fork/join thread pool, causing 4 subtasks to require at least 7 threads to execute concurrently.

For example, suppose a hotel has 400 rooms, a total of 4 cleaners, each worker can clean 100 rooms a day, so that 4 workers at full load, 400 rooms are all cleaned up exactly 1 days.

Fork/join's working mode is like this: first of all, the worker A is assigned 400 rooms of the task, he looked at the task too much of a person can not, so first 400 rooms split into two 200, then called to B, one of 200 points to B.

Immediately after, A and b again found 200 is also a big task, so a continue to divide 200 into two 100, and put one of 100 points to C, similar, B will be one of 100 points to ding, so that the final 4 people each divided into 100 rooms, concurrent execution is exactly 1 days.

If you change the wording:

// Call Fork () separately for the child task: subtask1.fork (); Subtask2.fork ();

This task will be divided! Wrong! The

For example, a 400 is divided into two 200, this kind of writing is equivalent to a 200 points to B, the other 200 points to C, and then, a supervisor, do not work, such as B and C finished his direct reporting work. B and C in the process of splitting 200 into two 100, they became the overseer, so that only 4 workers would have to live, now requires 7 workers to complete within 1 days, of which 3 are not working.

In fact, we look at the source of the JDK's invokeAll() methods can be found, InvokeAll n tasks, where the N-1 task will be used fork () to other threads execution, but it will also leave a task to execute themselves, so that the full use of the thread pool, Ensure that there are no idle threads to work with.

Fork/join Tasks for Java

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.