1. The most basic thread pool Threadpoolexecutor
How to use:
1 /**2 * Threadpoolexecutor Test class3 * Note:4 * 1, Threadpoolexecutor is a thread pool5 * 2, multiple tasks can be selected by the thread pool of several threads to execute6 */7 Public classThreadpoolexecutortest {8 Private StaticThreadpoolexecutor executor =9 NewThreadpoolexecutor (5, ten, Timeunit.seconds,NewArrayblockingqueue<runnable> (10));Ten One Public voidExecuteTask () { ATask1 Task1 =NewTask1 ();//Build Task 1 -Task2 Task2 =NewTask2 ();//Build Task 2 -Executor.execute (TASK1);//Perform task 1 theExecutor.execute (TASK2);//Perform task 2 - } - - /* + * Basic Task 2 - */ + classTask1Implementsrunnable{ A Public voidrun () { at //specific tasks of the business - for(inti=0;i<1000;i++){ -System.out.println ("Hello XXX!!!"); - } - } - } in - /* to * Basic Task 2 + */ - classTask2Implementsrunnable{ the Public voidrun () { * //specific tasks of the business $ for(inti=0;i<5;i++){Panax NotoginsengSystem.out.println ("Hello world2!!!"); - } the } + } A the Public Static voidMain (string[] args) { +Threadpoolexecutortest test =Newthreadpoolexecutortest (); - Test.executetask (); $ } $}View Code
Description
In the code, you build a thread pool (executor) and two tasks that implement the Runnable interface (Task1, Task2), and commit the two tasks to executor to execute.
The configuration of the thread pool: The working mechanism of the bottom of the collection and the parameters are described in detail.
Of course, the above results are interleaved because there is a thread switching.
2. Working mechanism
A, when a new task is committed to Threadpoolexecutor's execute () method, a new thread is created to handle the task if the thread running in the current pool is less than corepoolsize;
Note: This is a running thread in the pool, why do you say so? It's because the core thread is creating a thread for every task that comes up, and this looks at part three. After reading the third part, you will feel that, in fact, in other words: "If the current pool of threads less than corepoolsize" This will be more accurate, because we may be introduced in the following way the core thread is created in advance, if it is assumed that a task, When all the core threads are idle, the new thread is not created at this time.
B, if the thread in the current pool is greater than or equal to corepoolsize, but less than maximumpoolsize, if the queue is full, a new thread is created to handle the task, and if the queue is not full, the task is added to the queue;
C, if the queue is full, the number of running threads is equal to Maximumpoolsize, the task will be rejected (rebuffed)
3, Parameters detailed description
A, Corepoolsize and Maximumpoolsize
- If corepoolsize==maximumpoolsize, the size of the thread pool is fixed (this is similar to the designation of heap memory to prevent the loss of expansion, depending on the situation);
- By default, the core threads is created and started only when a new task arrives, but can be changed by Prestartcorethread and Prestartallcorethreads;
B, Threadfactory
- You can create a new thread by using Java.util.concurrent.ThreadFactory
- If no additional threadfactory is specified, the default executors#defaultthreadfactoryis used;
- With this default thread factory, all created threads are added to the same threadgroup, and these threads all have the same priority (Norm_priority), and are Non-daemon threads
Note: This together has a background (daemon) thread concept, a typical background thread: The garbage collection thread, which differs from other application threads in that the background thread disappears automatically when all the application threads are not available.
C, KeepAliveTime
- If the pool currently owns more threads than Corepoolsize, those threads will be terminated if they are idle (idle) outside the time greater than keepalivetime;
- This mechanism can reduce the waste of resources when the pool is not used actively;
- By default, the keep-alive mechanism will only be used when the number of threads exceeds corepoolsizethreads;
- Of course, this keep-alive mechanism can also be applied to the core threads by using Threadpoolexecutor#allowcorethreadtimeout (Boolean) (as long as KeepAliveTime >0)
D, Queue
Any kind of blockingqueue can be used to pass and store tasks that are submitted to the thread pool, with three kinds of queue policies:
1)synchronousqueue (default):
- Simply hand over the task to the thread instead of the queue, and if no thread is ready to process the task submitted to the pool immediately, a new thread is created to handle the task;
- This strategy requires maximumpoolsizes to ensure that the newly submitted tasks are not rejection;
- The biggest drawback to this approach is that the number of threads is soaring when the task arrives faster than the task is processed.
2) unbounded queue linkedblockingqueue:
- Because the queue is unbounded, when the running thread equals Corepoolsize, the new incoming task is queued without creating a new thread to execute (that is, the number of threads in the pool will never be greater than corepoolsize);
- The disadvantage of this approach is that the queue length is soaring when the task arrives faster than the task is processed.
3) bounded queue arrayblockingqueue:
- This way is very difficult to deal with a good way to consider the size of good arrayblockingqueue and the size of maximumpoolsize;
- When the Arrayblockingqueue is large and the maximumpoolsize is small, CPU utilization is reduced, OS resources are reduced, and context switches are reduced, but throughput is reduced. --the feature of fewer threads is this;
- If the task is frequently blocked (for example, they is I/O bound), more threads are needed;
- When the arrayblockingqueue is small and maximumpoolsize large, it makes the CPU busy but also encounters some unacceptable scheduling, and the throughput decreases.
Description: This collocation is a more troublesome place, will say behind.
E, rebuffed task
Perform a rejection scenario: Look at the starting part of the working mechanism.
When the task is rebuffed, the Execute () method invokes rejectedexecutionhandler#rejectedexecution. There are four kinds of handler strategies:
1) Threadpoolexecutor.callerrunspolicy: Call Execute () on the thread itself to handle the task
2) Threadpoolexecutor.discardpolicy: Tasks that cannot be performed are discarded directly
3) Threadpoolexecutor.discardoldestpolicy: If the executor is not closed, the task of the queue head will be discarded and the task will be added to the end of the team
4) Threadpoolexecutor. AbortPolicy (default): Reject task and throw exception
F, AOP
Threadpoolexecutor provides two methods for calling Threadpoolexecutor#beforeexecute and Threadpoolexecutor#afterexecute before and after each task is executed.
4. Apply the opening example
Thread pool parameters built in the instance:
- Corepoolsize==5
- maximumpoolsize==10
- keepalivetime==30s
- Queue: arrayblockingqueue, size 10
- Thread Factory: defaultthreadfactory (default)
- Rebuffed policy: AbortPolicy (default)
Set the working mechanism:
1) When <=5 tasks are submitted to executor (the number of tasks <=corepoolsize), Executor uses 5 core threads to perform these tasks;
2) When this time comes a task, if at this point 5 core threads have idle threads, is to use the idle thread to handle, if all busy, then the task into the queue;
3) Later on to the task, or as the second step to execute, until the task will fill the queue, this time, if another task, if the 5 core threads have idle threads, go directly to perform the task ( Note: The use of non-fair mode, if the use of fair mode, Should I go to the task of handling the queue head first and then join the task to the tail? This is a question for the time being, I'll look at the source code again to change , if the 5 core threads are busy, then create a new thread to perform the task;
4) If through the process above, the last 5 threads are busy, and the queue is full, and the pool of the number of threads is already 10 (the total number of threads in the ==maximumpoolsize), this time to implement the rebuffed strategy, here, using the default AbortPolicy, The task is discarded directly and an exception is thrown.
During the execution of the code, if you find that the 5 threads that were created later have not been called for more than 30 seconds, the thread is recycled.
Question: (This question I will after reading Threadpoolexecutor's relevant source code to answer)
When the queue is full, there is a task at this time, exactly 5 core threads have a free, then the following two kinds of situations which one is correct:
1) This idle core thread directly executes the task that has just arrived
2) This idle core thread executes the task of the queue head directly, and puts the task that has just arrived at the end of the team
Finally, here are the source resolution addresses for the two types of queues mentioned above:
Arrayblockingqueue: Eighth chapter arrayblockingqueue Source code Analysis
Linkedblockingqueue: Nineth Chapter Linkedblockingqueue Source code Analysis
12th Chapter Threadpoolexecutor Use and working mechanism