13. Thread Pool
The fourth way to get a thread: The thread pool, a executorservice, uses several possible pool threads to perform each submitted task, typically using the Executors factory method configuration.
The thread pool resolves two different issues: because of the reduced overhead of each task invocation, they typically provide enhanced performance when performing a large number of asynchronous tasks , and can also provide methods for binding and managing resources, including the threads used to execute the task set . Each threadpoolexecutor also maintains some basic statistical data, such as the number of completed tasks.
For ease of use across a wide range of contexts, this class provides a number of adjustable parameters and extension hooks (hooks). However, programmers are strongly advised to use the more convenient executors factory approach:
- Executors.newcachedthreadpool () (No boundary pool, automatic thread recovery is possible)
- Executors.newfixedthreadpool (int) (fixed size thread pool)
- Executors.newsinglethreadexecutor () (single background thread)
They all pre-defined settings for most usage scenarios.
Create a thread pool with 5 threads to increase the operation of the variable
/** Thread pool: Provides a thread queue that holds all waiting states in the queue. Avoids the additional overhead of creating and destroying and increasing the speed of response. * * Two, thread pool architecture: * Java.util.concurrent.Executor: Responsible for thread usage and scheduling root interface * |--**executorservice subinterface: main interface of thread pool * Implementation class for |--threadpoolexecutor thread pool * |--scheduledexecutorservice Sub-interface: Responsible for thread scheduling * |--scheduledt Hreadpoolexecutor: Inherit Threadpoolexecutor, implement Scheduledexecutorservice * Three, Tool class: Executors * Executorservice newFixedTh Readpool (): Create a fixed-size thread pool * executorservice Newcachedthreadpool (): Cache thread pool, the number of thread pools is not fixed, you can change the quantity automatically based on demand. * Executorservice Newsinglethreadexecutor (): Creates a single thread pool. There is only one thread in the thread pool * * Scheduledexecutorservice Newscheduledthreadpool (): Creates a fixed-size thread that can be deferred or timed to perform tasks. */ Public classTestthreadpool { Public Static voidMain (string[] args)throwsException {//1. Create a thread poolExecutorservice pool = Executors.newfixedthreadpool (5);ThreadPoolDemo TPD=NewThreadPoolDemo (); //2. Assigning a task to threads in a thread pool, >5, can call five threads of a line constructor for(inti = 0; I < 10; i++) {pool.submit (TPD); } //3. Close the thread poolPool.shutdown (); } //new Thread (TPD). Start ();//new Thread (TPD). Start ();}classThreadPoolDemoImplementsrunnable{Private inti = 0; @Override Public voidrun () { while(I <= 100) {System.out.println (Thread.CurrentThread (). GetName ()+ ":" + i++); } } }
Thread pool creates threads with callable and future
Public Static voidMain (string[] args)throwsException {//1. Create a thread poolExecutorservice pool = Executors.newfixedthreadpool (5); List<Future<Integer>> list =NewArraylist<>(); for(inti = 0; I < 10; i++) { //the Future object is used to receive the return value of the callable threadfuture<integer> future = Pool.submit (NewCallable<integer>(){ //thread call method, query 1-100 and@Override PublicInteger Call ()throwsException {intsum = 0; for(inti = 0; I <= 100; i++) {sum+=i; } returnsum; } }); List.add (future); } //Close the thread poolPool.shutdown (); //Traverse result set, output 10 times 5050 for(future<integer>future:list) {System.out.println (Future.get ()); } }
14. Thread Scheduling
The interface Scheduledexecutorservice inherits from the Executorservice interface, which is implemented by the Scheduledthreadpoolexecutor class (the subclass of the Threadpoolexecutor Class). You can schedule commands that run after a given delay or are executed on a regular basis.
Scheduledexecutorservice Newscheduledthreadpool (): Creates a fixed-size thread that can be deferred or timed to perform tasks.
Reference Java.util.concurrent.ScheduledThreadPoolExecutor.class in Schedule method source code
Public<V> scheduledfuture<v> Schedule (callable<v>Callable,Longdelay, Timeunit unit) { if(Callable = =NULL|| Unit = =NULL) Throw NewNullPointerException (); Runnablescheduledfuture<V> T =Decoratetask (callable,NewScheduledfuturetask<v>(callable, Triggertime (delay, unit))); Delayedexecute (t); returnT; }
Example:
Public classTestscheduledthreadpool { Public Static voidMain (string[] args)throwsException {//to create a thread pool object of type ScheduledexecutorserviceScheduledexecutorservice pool = Executors.newscheduledthreadpool (5);
for(inti = 0; I < 5; i++) { future<Integer> result = Pool.schedule (NewCallable<integer>() {@Override PublicInteger Call ()throwsException {intnum =NewRandom (). Nextint (100);//Generate random numbersSystem.out.println (Thread.CurrentThread (). GetName () + ":" +num); returnnum; } }, 1, timeunit.seconds);
System.out.println (Result.get ()); } //thread pool shutdownPool.shutdown (); } }
Forkjoinpool Branch Merge framework-work stealing
Fork/join framework: is to be a large task, when necessary, to split (fork) into a number of small tasks (split to No re-disassembly), and then the results of a small task operations to Join summary.
/* @since 1.7 * */ Public Abstract class Implements Future<v>, Serializable {...}
- use "work-stealing" mode (work-stealing): when you perform a new task, it splits it into smaller tasks, adds small tasks to the thread queue, and then steals one from the queue of a random thread and puts it in its own queue.
- The advantages of the Fork/join framework in relation to the general thread pool implementations are in the way that the tasks contained therein are handled. In a generic thread pool, a thread is waiting if a task that is being performed by a thread cannot continue to run for some reason. In the Fork/join framework implementation, a sub-problem cannot continue to run because it waits for the completion of another sub-problem. The thread that handles the sub-problem is actively looking for other sub-problems that are not yet running. This approach reduces thread latency and improves performance.
After jdk1.7, two fork/join frames are provided, and the maximum difference between two frames is whether there is a return value
// has a return value Public Abstract class extends Forkjointask<v> {}// no return value publicabstractclass extends forkjointask<void> {}
The following is an example of an implementation (for the sum of all the numbers between two numbers, such as 1-100-->5050):
classForkjoinsumcalculateextendsRecursivetask<long>{ Private Static Final LongSerialversionuid = -1812835340478767238l; Private Longstart; Private Longend; Private Static Final LongThurshold = 10000L;//Critical Value PublicForkjoinsumcalculate (LongStartLongend) { This. Start =start; This. end =end; } @OverrideprotectedLong Compute () {LongLength = end-start; //is less than the critical value, the sum of all the numbers between the initial value and the ending value is calculated directly without splitting if(Length <=thurshold) { Longsum = 0L; for(Longi = start; I <= end; i++) {sum+=i; } returnsum; }Else{//greater than the critical value, take the middle value to split, recursive call LongMiddle = (start + end)/2; Forkjoinsumcalculate Left=Newforkjoinsumcalculate (start, middle); Left.fork (); //to split and press into the thread queueForkjoinsumcalculate Right=NewForkjoinsumcalculate (middle+1, end); Right.fork (); // returnLeft.join () +Right.join (); } } }
Test 1-50000000000 's and:
Public Static void Main (string[] args) { = instant.now (); New Forkjoinpool (); ForkjointaskNew forkjoinsumcalculate (0L, 50000000000L); = Pool.invoke (Task); SYSTEM.OUT.PRINTLN (sum); = Instant.now (); System.out.println ("time-consuming:" + Duration.between (start, end). Tomillis ()); }
Result: CPU utilization reaches 100%, time consuming 19.361s
And for the For loop add a comparison:
Public void test1 () { = instant.now (); long sum = 0L; for (long i = 0L; I <= 50000000000L; i++) { + = i; } SYSTEM.OUT.PRINTLN (sum); = Instant.now (); System.out.println ("time-consuming:" + duration.between (start, end). Tomillis ()); // 35-3142-15704 }
The results are as follows: Time consuming 18.699s
Since the Fork/join framework is not easy to split in complex logic, JAVA8 has been improved for fork/join, as shown in the following code:
// java8 new Features publicvoid test2 () { = instant.now (); = longstream.rangeclosed (0L, 50000000000L) . Parallel () . Reduce (0L, long::sum); SYSTEM.OUT.PRINTLN (sum); = Instant.now (); System.out.println ("time-consuming:" + duration.between (start, end). Tomillis ()); // 1536-8118 }
Result: Time consuming 15.428s
Tested several values and found efficiency aspects: Java8 > For loop > Fork/join
|
10000000000L |
50000000000L |
100000000000L |
Java8 |
3320ms |
15428ms |
34770ms |
For |
3902ms |
18699ms |
37858ms |
Fork/join |
4236ms |
19361ms |
40977ms |
Logically, as the computational volume increases, the efficiency of the fork/join will exceed the for loop, but the result of the native test is that the Fork/join framework is always less efficient than the for loop at the bottom. This aspect may lie in the compute method design in the long type of packing and unpacking has a certain time cost, on the other hand may because the critical value selection is unreasonable, the test is selected 10000, in the test 10000000000L accumulation, the use of four critical values: 5000, 10000, 20000, 100000, the result is the most efficient when the critical value is 10000. Still believe that seeing is the truth.
(iv) JUC thread advanced Features-thread pool/thread scheduling/Forkjoinpool