Summary: The thread pool is characterized by the number of threads =corepoolsize, only after the task queue is full, a task is removed from the task queue, and then a new thread is constructed, and the cycle repeats until the number of thread reaches Maximumpoolsize to execute the deny policy.
Thread Pool-intsmaze
The idea of the thread pool is to create an area in the system that holds a number of standby threads, which are called thread pools. If there is a task that needs to be performed, a standby thread is borrowed from the thread pool to perform the specified task, and the borrowed thread can be returned to the end of the task. This avoids the large number of repeatedly creating thread objects, wasting CPU, memory resources.
Custom thread pool-intsmaze
If you look at the source implementations of the various thread pools provided by the JDK, you can see that, in addition to the JDK8 new thread pool Newworkstealingpool, it is based on the encapsulation implementation of Threadpoolexecutor. So we first explain the specific functions of threadpoolexecutor.
Threadpoolexecutor detailed-intsmaze
Threadpoolexecutor (Corepoolsize, maximumpoolsize, keepalivetime, timeunit unit, blockingqueue<runnable > WorkQueue, threadfactory threadfactory, Rejectedexecutionhandler handler)
Corepoolsize: Specifies the number of threads in the thread pool
Maximumpoolsize: Maximum number of threads
KeepAliveTime: When the number of threads exceeds corepoolsize, more idle threads will survive (over this time, the idle thread is destroyed).
Unit:keepalivetime Unit of Time
WorkQueue: Task queue, Task submitted but not executed
Threadfactory: Thread factory that creates threads, by default
Handler: Deny policy, when too many tasks too late to process, how to reject the task, the default is the new AbortPolicy () policy.
Executorservice es = new Threadpoolexecutor (3, 8, 60L, timeunit.seconds, New linkedblockingqueue<runnable> () , executors.defaultthreadfactory (), new Rejectedexecutionhandler () {public void rejectedexecution ( Runnable R, threadpoolexecutor executor) { System.out.println ("Discard"); } });
Task Queue--store runnable objects-intsmaze
Summary: The thread pool is characterized by the number of threads =corepoolsize, only after the task queue is full, a task is removed from the task queue, and then a new thread is constructed, and the cycle repeats until the number of thread reaches Maximumpoolsize to execute the deny policy.
As long as the queue implements the Blockingqueue interface, note that Concurrentlinkedqueue implements the topmost queue interface so it cannot be used here.
Commonly used are the following:
Synchronousqueue: The direct submission queue, the queue does not have capacity, each insert operation waits for a corresponding delete operation, conversely, each delete operation waits for the corresponding insert operation. So he does not save the task, always submit the task to the thread execution, if there is no idle thread, creates a new thread, and when the number of threads reaches the maximum, the Deny policy is executed.
arrayblockingqueue: bounded task queue, thread pool has fewer threads than Corepoolsize, creates a new thread, greater than Corepoolsize, joins the new task into the wait queue. If the wait queue is full, a new thread execution task is created, and a deny policy is executed greater than maximumpoolsize, if the bus path is not larger than maximumpoolsize.
linkedblockingqueue: unbounded queue, unless the system resources are exhausted, there is no task queued failure situation. The thread pool has fewer threads than corepoolsize, then a new thread is created, greater than corepoolsize, and the new task is added to the wait queue.
Priortyblockingqueue: priority queue, which can control the execution order of tasks, is unbounded queue. Arrayblockingqueue,linkedblockingqueue are all in accordance with the FIFO algorithm to deal with the task, Priorityblockingqueue can be based on the priority of the task itself executed successively.
Deny Policy-intsmaze
When a thread in a thread pool has run out of time, while waiting for a task in the queue to fill up and no longer fit into a new task, you need to reject the policy: the processing is handled when the number of tasks exceeds the actual capacity of the system.
There are four types of rejection policies built into the JDK:
AbortPolicy: Throws the exception directly (the default policy), even if the thread pool is idle, the subsequent threads cannot be run, and the subsequent thread can run, to catch the exception information.
Callerrunspolicy: This policy runs the currently discarded task directly in the caller's thread. Obviously this does not really discard the task, but the performance of the task submission thread is highly likely to drop sharply.
Discardoldestpolicy: Discards the oldest request, which is a task that is about to be executed, and attempts to commit the current task again.
Discardpolicy: Silently discard the tasks that cannot be handled, without any processing. If the task is allowed to be lost, this may be the best solution. When the online pool is not idle, the submitted tasks are discarded, and the submitted task executes when there are idle threads.
Below is the JDK's reject policy source code-intsmaze
public static class Callerrunspolicy implements Rejectedexecutionhandler {public callerrunspolicy () {} /** * Run the currently discarded task directly in the caller thread */public void Rejectedexecution (Runnable R, Threadpoolexecutor e) { if (!e.isshutdown ()) {R.run (); }}} public static class AbortPolicy implements Rejectedexecutionhandler {public AbortPolicy () {} public void Rejectedexecution (Runnable R, Threadpoolexecutor e) {throw new Rejectedexecutionexception ("T Ask "+ r.tostring () +" rejected from "+ E.tostring ()); }} public static class Discardpolicy implements Rejectedexecutionhandler {public discardpolicy () {} /** * Does Nothing, which have the effect of discarding task R. */public void Rejectedexecution (Runnable R, Threadpoolexecutor e) {} } public static class Discardoldestpolicy implements Rejectedexecutionhandler {public discardoldestpolicy () {}/** * discards the oldest request, a task that is about to be executed, and attempts to commit the current task again. */public void Rejectedexecution (Runnable R, Threadpoolexecutor e) {if (!e.isshutdown ()) { E.getqueue (). poll (); E.execute (R); } } }
Summary: Under the AbortPolicy strategy, we want to catch exceptions so that we can capture which tasks are discarded. If you use a different strategy, the discarded task cannot be located, only through the following program Es.submit (new MyTask (i)), the task is printed before the task, the run () logic that runs the task is, in the print task information, two log alignment to locate which tasks are discarded.
public class MyTask implements runnable{private int number; public MyTask (int number) {super (); This.number = number; } public void Run () {System.out.println (System.currenttimemillis () + "thread ID:" +thread.currentthread (). GetId () + "= = =" +number); try {thread.sleep (1000); } catch (Interruptedexception e) {e.printstacktrace (); }}} public static void Main (string[] args) {//Executorservice es=new threadpoolexecutor (5,5,60l, Timeunit. SECONDS,//New arrayblockingqueue<runnable> (1), Executors.defaultthreadfactory (), New THREADPOOLEXECU Tor. AbortPolicy ()); Executorservice es=new threadpoolexecutor (5,5,60l, timeunit.seconds,//new arrayblockingqueue< Runnable> (5), Executors.defaultthreadfactory (), New Threadpoolexecutor.callerrunspolicy ()); Executorservice es=new threadpoolexecutor (5,5,60l, timeunit.seconds,//nEW arrayblockingqueue<runnable> (5), Executors.defaultthreadfactory (), New Threadpoolexecutor.discardpolicy () ); Executorservice es=new threadpoolexecutor (5,5,60l, timeunit.seconds, new arrayblockingqueue<runnable> (5), Executors.defaultthreadfactory (), New Threadpoolexecutor.discardoldestpolicy ()); for (int i=0;i<10000;i++) {try {System.out.println (i); Es.submit (New MyTask (i)); Thread.Sleep (100); } catch (Exception e) {e.printstacktrace (); System.out.println ("------------------------" +i); } } }
Thread pool execution Logic source parsing-intsmaze
Public future<?> Submit (Runnable Task) {if (task = = null) throw new NullPointerException (); runnablefuture<void> ftask = newtaskfor (task, NULL); Execute (ftask); return ftask; }/** * Executes the given task sometime in the future. The task * May, execute in a new thread, or in an existing pooled thread. * * If The task cannot is submitted for execution, either because this * executor have been shutdown or because its Capacity has been reached, * the task was handled by the current {@code Rejectedexecutionhandler}. * * @param command the task to execute * @throws rejectedexecutionexception at discretion of * {@code Rejectedexecutionhandler}, if the task * cannot is accepted for execution * @throws NullPointerException I f {@code command} is null */public void execute (Runnable command) {if (command = = null) throw n EW NullPointerException (); /* * Proceed in 3 steps: * * 1. If fewer than corepoolsize threads is running, try to * start a new thread with the given command as its first * Task. The call to Addworker atomically checks runstate and * workercount, and so prevents false alarms that would add * Threads when it shouldn ' t, by returning false. * If fewer than corepoolsize threads are running, first try starting a new thread task with the given command. Automatic call Addworker check runstate and Workercount, * 2. If a task can be successfully queued, then we still need * to double-check whether we should has added a thread * (because existing ones died since last checking) or which * the pool shut down since entry to this Metho D. We * recheck state and if necessary rolled back the enqueuing if * stopped, or start a new thread if T Here is none. * If the task can be queued successfully, then we still need to check carefully whether we should add a thread (because the existing one has died since the last check) or that the pool has been closed since it entered the method. So IRe-check the status, if necessary, the rollback queue stops, or if not, start a new thread. * 3. If We cannot the queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */int c = Ctl.get (); if (Workercountof (c) < corepoolsize) {if (Addworker (command, True)) return; c = Ctl.get (); } if (IsRunning (c) && workqueue.offer (command)) {int recheck = Ctl.get (); if (! isrunning (Recheck) && Remove (command)) reject (command);//queue full, execute deny policy else if (work Ercountof (recheck) = = 0) Addworker (null, FALSE); } else if (!addworker (command, False)) reject (command); The final void reject (Runnable command) {handler.rejectedexecution (command, this);//This is the method that calls our incoming deny policy object} /** * Dispatch An uncaught exception to the handler. THe method is * intended to being called only by the JVM. */private void Dispatchuncaughtexception (Throwable e) {Getuncaughtexceptionhandler (). Uncaughtexception (This, E ); }
Thread pool Implementation class-intsmaze for JDK
Newfixedthreadpoo-intsmaze
The task queue is in Linkedblockingqueue (infinite length), with the same number of threads and the maximum number of threads. Function reference the previous Task queue summary.
Executorservice Es=executors.newfixedthreadpool (5);//parameter specifies that thread pool threads are 5 and the maximum number of threads is 5public static Executorservice Newfixedthreadpool (int nthreads) { return new Threadpoolexecutor (Nthreads, Nthreads, 0L, Timeunit.milliseconds, new linkedblockingqueue<runnable> ());}
Newsinglethreadexecutor-intsmaze
Task Queue Linkedblockingqueue (unlimited length), both the number of threads and the maximum number of threads are 1.
Executorservice es=executors.newsinglethreadexecutor ();//thread pool The number of threads and the maximum number of threads is 1.public static Executorservice Newsinglethreadexecutor () { return new Finalizabledelegatedexecutorservice ( new Threadpoolexecutor (1, 1, 0L, Timeunit.milliseconds, new Linkedblockingqueue<runnable> ()));}
Newcachedthreadpool-intsmaze
The task queue is synchronousqueue, the number of threads is 0, and the maximum number of threads is integer.max_value, so a new thread is created whenever there is no idle thread on the task.
Executorservice Es=executors.newcachedthreadpool ();//Specifies that thread pool threads are 0 and the maximum number of threads is integer.max_value. The task queue is synchronousqueuepublic static Executorservice Newcachedthreadpool () { return new Threadpoolexecutor (0, Integer.max_value, 60L, Timeunit.seconds, new synchronousqueue<runnable> ());}
newscheduledthreadpool--timed thread-intsmaze
The task queue is new Delayedworkqueue (), and the returned object expands on the Executorservice interface to perform certain functions at a specified time, executing or periodically executing a task after a fixed delay.
public static Scheduledexecutorservice newscheduledthreadpool (int corepoolsize) { return new Scheduledthreadpoolexecutor (corepoolsize);} Public scheduledthreadpoolexecutor (int corepoolsize) { super (corepoolsize, Integer.max_value, 0, nanoseconds, new Delayedworkqueue ());} Public threadpoolexecutor (int corepoolsize, int maximumpoolsize, long KeepAliveTime, timeunit Unit, blockingqueue<runnable> WorkQueue) {This (corepoolsize, maximumpoolsize, KeepAliveTime, Unit, WorkQueue, executors.defaultthreadfactory (), DefaultHandler);}
Newsinglethreadscheduledexecutor--timed thread-intsmaze
the equivalent of corepoolsize in Newscheduledthreadpool (int corepoolsize) is set to 1.
Scheduledexecutorservice Es=executors.newsinglethreadscheduledexecutor ();
Delay thread Pool
Class Myscheduledtask implements runnable{private string tname; public myscheduledtask (String tname) { this.tname= Tname; The public void Run () { System.out.println (tname+) task is deferred for 2 seconds!!! "); }} public class intsmaze{public static void Main (string[] args) { scheduledexecutorservice scheduledthreadpool = Executors.newscheduledthreadpool (2); Myscheduledtask mt1=new myscheduledtask ("MT1"); Scheduledthreadpool.schedule (Mt1,2,timeunit.seconds); }}
newworkstealingpool java8 New connection pool-intsmaze
public static executorservice newworkstealingpool (int parallelism) { return new Forkjoinpool (parallelism, forkjoinpool.defaultforkjoinworkerthreadfactory, null, TRUE); } Creates a specified number of thread pools to perform a given level of parallelism, and also uses multiple queues to reduce competition public static Executorservice Newworkstealingpool () { return new Forkjoinpool (Runtime.getruntime (). Availableprocessors (), Forkjoinpool.defaultforkjoinworkerthreadfactory, null, TRUE); } The simplification of the previous method, if the current machine has 4 CPUs, the target's parallel level is set to 4.
Turn off the thread pool (rarely used, except when switching data sources to control)-intsmaze
You want the program to exit after all tasks have been performed, call the shutdown (), Shutdownnow () method in the Executorservice interface.
After you run out of a thread pool, you should call the shutdown method of the thread pool and start the shutdown sequence of the thread pool. When the shutdown method is called, the thread pool is not receiving new tasks, but all previously submitted tasks are executed. When all the tasks in the thread pool are executed, all threads in the thread pool die; The Shutdownnow method tries to stop all active tasks that are being performed, pauses processing of the awaited task, and returns a list of tasks waiting to be executed.
Thread pool Optimization-intsmaze
In general, determining the size of the thread pool requires considerations such as the number of CPUs, memory size, JDBC connectivity, and so on. In the Java Concurrency Programming practice, an empirical formula for estimating the size of a thread pool is given in this book:
Number of NCPU=CPU
ucpu= utilization of Target CPU, 0<=ucpu<=1
W/c= ratio of wait time to calculation time
To maintain the processor's desired usage rate, the optimal thread pool size equals:
nthreads=ncpu*ucpu* (1+W/C)
In Java, you can use the
Runtime.getruntime (). Availableprocessors ()
Gets the number of CPUs that can be.