Differences between using a thread pool and not using a thread pool
Let's take a look at the difference between using the thread pool and not adapting to the thread pool, the first piece of code is using the thread pool:
PublicStaticvoidMain (string[] args) {Long StartTime =System.currenttimemillis ();Final list<integer> L =New linkedlist<integer>(); Threadpoolexecutor TP =New Threadpoolexecutor (100, 100, 60, Timeunit.seconds,New Linkedblockingqueue<runnable> (20000));final random random = new Random (); for (int i = 0; i < 20000; I++new Runnable () {public void run () {L.add (Random.nextint ());}}); } tp.shutdown (); try {tp.awaittermination (1 catch (Interruptedexception e) {e.printstacktrace ();} System.out.println (System.currenttimemillis ()- StartTime); System.out.println (L.size ());}
Next, the thread pool is not used:
PublicStaticvoidMain (string[] args) {Long StartTime =System.currenttimemillis ();Final list<integer> L =New linkedlist<integer> (); final random random = new Random (); for (int i = 0; i < 20000; I++new thread () {public void run () {L.add (Random.nextint ());}}; Thread.Start (); try {Thread.Join ();} catch (Interruptedexception e) {e.printstacktrace ();}} System.out.println (System.currenttimemillis ()- StartTime); System.out.println (L.size ());}
Run, my first code here the thread pool time is 194ms, the second code does not use the thread pool time is 2043ms. The number of threads in the default thread pool here is 100, and if this number is reduced, the system's ability to process data becomes weaker, but the speed is even faster. Of course, the example is simple, but it's enough to explain the problem.
The role of the thread pool
The thread pool works on 2:
1, reduce the number of times to create and destroy threads, each worker thread can be reused, perform multiple tasks
2, according to the system's ability to withstand, adjust the thread pool of work thread data, to prevent the server crashes because of excessive memory consumption
Use the thread pool to set the number of threads manually or automatically, depending on the environment of the system. Less system operating efficiency is not high, the system congestion, more memory. Use the thread pool to control the number and other threads to wait. A task is completed, and then the first task from the queue starts executing. If the task is not waiting for a task, the thread pool resource is waiting. When a new task needs to be run, if there are waiting worker threads in the thread pool, it can start running, otherwise enter the wait queue.
Thread pool class Structure
Draw a diagram representing the class structure of the thread pool:
This diagram basically simply represents the structure of the thread pool class:
1, the most top-level interface is executor, but executor is strictly not a thread pool but only provides a mechanism for how the task works
2, Executorservice can be considered as a real thread pool interface, interface provides a way to manage the thread pool
3, the following two branches, Abstractexecutorservice branch is a common thread pool branch, Scheduledexecutorservice is used to create a timed task
Threadpoolexecutor
This article focuses on the thread pool Threadpoolexecutor, the beginning also demonstrates the use of Threadpoolexecutor, the following is a look at the Threadpoolexecutor complete construction method of the signature and to understand each of the role of each parameter to Understanding Threadpoolexecutor:
Public threadpoolexecutor (int corepoolsize, int maximumpoolsize, long KeepAliveTime, Timeunit unit, blockingqueue<runnable> workQueue, Threadfactory threadfactory, Rejectedexecutionhandler handler)
Take a look at the meaning of each parameter from the JDK API:
1, Corepoolsize
Number of threads held in the pool, including idle threads
2, Maximumpoolsize
Maximum number of threads allowed in the pool
3, KeepAliveTime
When the number of threads is greater than corepoolsize, the maximum time to wait for a new task before terminating the extra idle thread
4. Unit
KeepAliveTime Time Unit
5, WorkQueue
To store tasks that have not yet been performed
6, Threadfactory
The factory used when the execution program creates a new thread
7, Handler
Handlers that are used when execution is blocked due to out-of-range and queue capacity
The above content, it seems corepoolsize and maximumpoolsize is not very good to understand, so in particular, four rules to explain the two parameters:
1, the number of threads in the pool is less than corepoolsize, new tasks are not queued but add new threads directly
2, the number of threads in the pool is greater than or equal to corepoolsize,workqueue, preferred to new tasks if workqueue instead of adding new threads
3, the pool thread number is greater than or equal to Corepoolsize,workqueue, but the number of threads is less than maximumpoolsize, add a new thread to handle the task being added
4, the pool thread number is greater than Corepoolsize,workqueue is full, and the number of threads is greater than or equal to Maximumpoolsize, the new task is rejected, using handler to process the rejected task
The use of Threadpoolexecutor is simple, and the previous code has written an example. Use the Execute (Runnable command) method to initiate the execution of a task, using the shutdown () method to make a valid shutdown of the submitted task. Although the thread pool is good, let's take a look at the JDK API:
Programmers are strongly advised to use the more convenient executors factory method Executors.newcachedthreadpool () (without a thread pool, which can be automatically recycled by threads), Executors.newfixedthreadpool (int) (fixed-size thread pool) and Executors.newsinglethreadexecutor () (a single background thread) that have predefined settings for most usage scenarios.
So, jump to Threadpoolexecutor's attention (or that sentence, query the JDK API), and focus on the executors recommended by the JDK.
Executors
Personally, the focus of the thread pool is not how to use the Threadpoolexecutor or how to use the executors, but to use the appropriate thread pool in the right scenario, the so-called "proper thread pool" means, Threadpoolexecutor constructs a different thread pool to meet the needs of use by passing in different parameters .
Here's a look at some of the thread pools executors provides to users:
1. Newsinglethreadexecutos () single thread pool
Static Executorservice Newsinglethreadexecutor () { new Finalizabledelegatedexecutorservice ( New Threadpoolexecutor (1, 1, 0Lnew linkedblockingqueue<runnable>()));}
Single thread thread pool, the number of threads running in the thread pools is definitely 1. Workqueue Select unbounded Linkedblockingqueue, then no matter how many tasks are queued, the previous task executes, then executes the threads in the queue. From this point of view, the second parameter maximumpoolsize is meaningless, because Maximumpoolsize describes a queue of tasks more than workqueue capacity, the thread pool can accommodate up to maximumpoolsize tasks, and now Workqueue is unbounded, that is, the queue of the task will never more than workqueue capacity, that maximum actually set how much does not matter
2, Newfixedthreadpool (int nthreads) fixed size thread pool
Static Executorservice newfixedthreadpool (int nthreads) { new threadpoolexecutor (Nthreads, Nthreads, 0Lnew linkedblockingqueue<runnable>());}
A fixed-size thread pool is similar to a single-threaded thread pool, and is nothing more than a manually specified nthreads that is programmed by threads that can run in thread pools. Similarly, because the Linkedblockingqueue is selected, the second parameter maximumpoolsize is also meaningless.
3. Newcachedthreadpool () no boundary pool
Static Executorservice Newcachedthreadpool () { new Threadpoolexecutor (0, Integer.max_value, 60L New synchronousqueue<runnable>());}
The pool without boundaries means that no matter how many tasks are submitted, they run directly. No boundary pool uses synchronousqueue, the thread pool does not have workqueue capacity one said, as long as the added threads will be taken. Since it is a pool without boundaries, the number of threads must not be capped, so the main maximumpoolsize, set as an approximate infinite large integer.max_value. Also note that the single thread pool and fixed-size thread pool threads are not automatically recycled, that is, the task of ensuring that the incoming tasks will eventually be processed, but as to when to deal with, it depends on the processing power. However, the no-limit pool is set to reclaim time, and since corepoolsize is 0, threads that are not used for 60 seconds are removed directly
Talk about Workqueue
The above three thread pools all mention a concept, workQueue, which is the queuing strategy. The queuing policy describes how threads are queued to be run when the current thread is greater than corepoolsize.
There are three strategies queued: direct commit, bounded queue, unbounded queue.
In the latter two, the JDK uses the unbounded queue Linkedblockingqueue as Workqueue instead of the bounded queue Arrayblockingqueue, although the latter can control the resources, but personally think that There are three disadvantages to using a bounded queue than a unbounded queue:
1, the use of bounded queue, corepoolsize, maximumpoolsize two parameters are bound to be based on the actual scene constantly adjusted to achieve an optimal, which will inevitably bring great trouble to the development, must undergo a lot of performance testing. So simply use the unbounded queue, the task is always added to the queue, will not overflow, natural maximumpoolsize is no use, just need to adjust according to the system processing power corepoolsize can be
2, to prevent business spikes. Especially in Web applications, there are times when sudden mass requests come to normal. At this point, the unbounded queue is used, at least to ensure that all tasks can be processed, sooner or later. But what about using a bounded queue? Those tasks that go beyond maximumpoolsize are discarded, slow to deal with, but the task is not dealt with directly, which seems a bit bad
3, not only corepoolsize and maximumpoolsize need to adjust each other, bounded queue size and maximumpoolsize also need to compromise, this is a more difficult to control and adjust the aspect
Of course, at the end of the sentence, like the contrast between comparable and comparator, synchronized and Reentrantlock, and then here the unbounded queue and the comparison of bounded queues, seemingly have a slightly more prominent advantages, But this is by no means encouraging people to use one without using another, and everything needs to be based on reality, and of course, at the very beginning, you can focus on what seems to be an obvious advantage.
Four rejection strategies
The so-called rejection strategy has been mentioned before, too many tasks, more than maximumpoolsize how to put? Of course, the answer is no more, then only refused. When rejecting, you can specify a deny policy, which is a handler.
The parent interface of the deny policy is REJECTEDEXECUTIONHANDLER,JDK itself in the Threadpoolexecutor to provide users with four kinds of rejection policy, look at:
1, AbortPolicy
Throw a rejectedexecutionexception directly, which is also the default for the JDK deny policy
2, Callerrunspolicy
Try to run the rejected task directly, and if the thread pool is closed, the task is discarded.
3, Discardoldestpolicy
Remove the last task that was not processed, and then perform the rejected task. Similarly, if the thread pool is closed, the task is discarded.
4, Discardpolicy
Tasks that cannot be performed will be deleted
Java Multi-Threading 18: Thread pool