Recently studied the next threadpoolexecutor, found that there are some areas to be pondered. First move the JDK1.6 document here.
One ExecutorService
, it uses a number of possible pool threads to perform each submitted task, usually 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, it is strongly recommended that programmers use a more convenient Executors
factory method Executors.newCachedThreadPool()
(no thread pool, automatic thread recycling), Executors.newFixedThreadPool(int)
(fixed-size thread pool), and Executors.newSingleThreadExecutor()
(a single background thread), which are pre-defined settings for most usage scenarios. Otherwise, when you manually configure and adjust this class, use the following guidelines:
Core and Maximum pool size
The threadpoolexecutor will getCorePoolSize()
getMaximumPoolSize()
automatically adjust the pool size based on the boundaries set by Corepoolsize (see) and maximumpoolsize (see). When a new task is committed in a method execute(java.lang.Runnable)
, if the running thread is less than corepoolsize, a new thread is created to process the request, even if the other worker threads are idle. If you run more threads than corepoolsize and less than maximumpoolsize, a new thread is created only when the queue is full. If you set the same corepoolsize and Maximumpoolsize, a fixed-size thread pool is created. If you set Maximumpoolsize to a basic unbounded value (such as Integer.max_value), the pool is allowed to accommodate any number of concurrent tasks. In most cases, the core and maximum pool sizes are only set based on constructs, but can also be used setCorePoolSize(int)
and setMaximumPoolSize(int)
dynamically changed.
On-Demand construction
By default, a method can be used prestartCoreThread()
or dynamically overridden, even if the core thread was initially created and started only when a new task arrives prestartAllCoreThreads()
. If you construct a pool with a non-empty queue, you may want to pre-start the thread.
Create a new thread
Use to ThreadFactory
create a new thread. If not otherwise stated, the create thread is used in the same ThreadGroup
Executors.defaultThreadFactory()
, and the threads have the same norm_priority priority and non-daemon state. By providing different threadfactory, you can change the name of the thread, the thread group, the priority, the daemon state, and so on. If threadfactory fails to create a thread when returning null from Newthread , the executor continues to run, but cannot perform any tasks.
Keep Active Time
If there are currently more than corepoolsize threads in the pool, these extra threads will terminate when the idle time exceeds KeepAliveTime (see getKeepAliveTime(java.util.concurrent.TimeUnit)
). This provides a way to reduce resource consumption when the pool is inactive. If the pool becomes more active later, you can create a new thread. You can also use methods to setKeepAliveTime(long, java.util.concurrent.TimeUnit)
dynamically change this parameter. Use TimeUnit.NANOSECONDS
the value of Long.max_value to effectively disable idle threads from the previous termination state before closing. By default, the Keep-active policy is applied only when there are more than corepoolsizethreads threads. However, the allowCoreThreadTimeOut(boolean)
method can also apply this time-out policy to the core thread as long as the KeepAliveTime value is not 0.
Queuing
-
All blockingqueue
can be used to transfer and persist submitted tasks. You can use this queue to interact with the pool size:
Is queued with three common policies:
-
If you run fewer threads than Corepoolsize, Executor always prefers to add new threads without queuing.
-
If you are running a thread that is equal to or more than corepoolsize, Executor always prefers to join the request to the queue without adding a new thread.
-
If the request cannot be queued, a new thread is created unless the thread is created beyond maximumpoolsize, in which case the task is rejected.
-
submit directly. The default option for the work column is Synchronousqueue
, which will submit tasks directly to the thread without maintaining them. Here, if there is no thread available to run the task immediately, attempting to join the task to the queue will fail, and a new thread will be constructed. This policy avoids locking when processing a set of requests that may have internal dependencies. Direct submissions typically require unbounded maximumpoolsizes to avoid rejecting newly submitted tasks. This policy allows the possibility of an increase in the number of lines that are allowed to continue when the command arrives in a row that exceeds the average that the queue can handle.
-
unbounded queues. using unbounded queues (for example, linkedblockingqueue
without a predefined capacity) causes all corepoolsize threads to be busy waiting in the queue. This way, the created thread will not exceed corepoolsize. (therefore, the value of the maximumpoolsize is not valid.) When each task is completely independent of other tasks, that is, when task execution does not affect each other, it is appropriate to use a unbounded queue, for example, in a Web page server. This queueing can be used to handle transient burst requests, which allow the possibility of an increase in the number of lines that are allowed to occur when the command reaches an average of more than the queue can handle.
-
bounded queues. when using limited maximumpoolsizes, bounded queues such as arrayblockingqueue
help prevent resource exhaustion, but can be difficult to adjust and control. The queue size and maximum pool size may need to be compromised: using large queues and small pools minimizes CPU usage, operating system resources, and context switching overhead, but can result in artificially reduced throughput. If tasks are frequently blocked (for example, if they are I/O boundaries), the system may schedule more threads than you permit. Using small queues typically requires a large pool size, high CPU utilization, but may encounter unacceptable scheduling overhead, which also reduces throughput.
Rejected tasks when Executor is closed and Executor uses a limited boundary for maximum thread and work queue capacity and is already saturated, new tasks that are submitted in method execute (java.lang.Runnable) are rejected. In both of these cases, the Execute method calls its Rejectedexecutionhandler rejectedexecutionhandler.rejectedexecution (java.lang.Runnable, Java.util.concurrent.ThreadPoolExecutor) method. There are four predefined handler policies available: It is also possible to define and use other kinds of rejectedexecutionhandler classes, but doing so requires great care, especially when the policy is used only for specific capacity or queueing policies.
In the default ThreadPoolExecutor.AbortPolicy
, the handler is rejected and the runtime is thrown RejectedExecutionException
.
In ThreadPoolExecutor.CallerRunsPolicy
, the thread invokes the execute itself that runs the task. This strategy provides a simple feedback control mechanism that can slow down the submission of new tasks.
In ThreadPoolExecutor.DiscardPolicy
, the tasks that cannot be performed are deleted.
In ThreadPoolExecutor.DiscardOldestPolicy
, if the execution program has not been closed, the task that is in the head of the work queue is deleted, and then the program is retried (repeat this process if it fails again).
Hook method This class provides protected overridable BeforeExecute (Java.lang.Thread, java.lang.Runnable) and AfterExecute (Java.lang.Runnable, Java.lang.Throwable) method, which is called before and after each task is executed. They can be used to manipulate the execution environment, for example, reinitialize ThreadLocal, collect statistics, or add log entries. In addition, you can override method terminated () to perform all special processing that needs to be done after the Executor is completely terminated. If the hook or callback method throws an exception, the internal worker thread fails sequentially and terminates abruptly. Queue Maintenance Method Getqueue () allows access to work queues for monitoring and debugging purposes. Strongly oppose the use of this method for any other purpose. Both the Remove (java.lang.Runnable) and Purge () methods can be used to help with storage reclamation when a large number of queued tasks are canceled. Terminating the program and no longer referencing the pool without the remaining threads is automatically shutdown. If you want to make sure that you recycle the dereferenced pool (even if the user forgets to call shutdown ()), you must schedule the unused thread to end: Set the appropriate keep-active time, use the lower bounds of the 0 core thread, and/or set Allowcorethreadtimeout (Boolean).
Use Synchronousqueue as a queue in the thread pool package com.jzli.threadpool;import java.util.linkedlist;import java.util.list;import java.util.concurrent.future;import java.util.concurrent.synchronousqueue; import java.util.concurrent.threadpoolexecutor;import java.util.concurrent.timeunit;import org.apache.log4j.logger;import com.jzli.threadpool.task.sleeptask;/** * Test the Threadpoolexecutor thread pool (executors.newcachedthreadpool ()) using Synchronousqueue. * test Results: Set the maximum number of threads to Integer.max_value, each task creates a new thread execution, and the test discovery thread is not destroyed. * Test Conclusion: Not recommended, will cause waste of resources . * * Official Document Description: Submit directly. The default option for the work queue is synchronousqueue, which will submit tasks directly to the thread without maintaining them. * here, if there is no thread available to run the task immediately, attempting to join the task to the queue will fail, so a new thread * will be constructed. This policy avoids locking when processing a set of requests that may have internal dependencies. Direct submissions typically require unbounded maximumPoolSizes * to avoid rejecting newly submitted tasks. This policy allows the possibility of an increase in the number of lines that are allowed to continue when the command arrives in a row that exceeds the average that the queue can handle. * * @author lijinzhao * */public class ThreadpoolexecutortestwithsYnchronousqueue {private static final logger _log = logger.getlogger ( Threadpoolexecutortestwithsynchronousqueue.class);p Ublic static void main (String[] args) throws exception {new threadpoolexecutortestwithsynchronousqueue (). Test ();} Public void test () throws Exception {ThreadPoolExecutor threadPool = null;// uses the Synchronousqueue queue to create new threads to complete tasks and automatically destroys threads (??? Not automatically destroyed in the experiment) Threadpool = new threadpoolexecutor (0, integer.max_value, 1800, Timeunit.seconds, new synchronousqueue<runnable> (),new Threadpoolexecutor.discardoldestpolicy ());// threadpool = new threadpoolexecutor (CoreSize, maxSize, 30L,// TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable> (300),// new threadpoolexecutor.discardoldestpolicy ());// threadpool = (ThreadPoolExecutor) executors.newcachEdthreadpool (); List<future<integer>> list = new linkedlist<future<integer>> (); for (int i = 1; i <= 500; i++) {list.add (ThreadPool.submit (new sleeptask (i), i));} Int count = 0;do {count = threadpool.getactivecount (); TimeUnit.SECONDS.sleep (1);} while (count > 0);for (future<integer> future : list) { Try {_log.info ("result=" + future.get ());} catch (exception e) {_log.error (e, e);}} _log.info (Threadpool.getpoolsize ()); TimeUnit.SECONDS.sleep, _log.info ("====================================="); _log.info (threadpool.getpoolsize ());list = new linkedlist<future<integer>> ();for (int i = 1; i <= 100; i++) {list.add (Threadpool.submit (New sleeptask (i), i));} Count = 0;do {count&nBsp;= threadpool.getactivecount (); TimeUnit.SECONDS.sleep (1);} while (count > 0); _log.info (Threadpool.getpoolsize ()); Threadpool.shutdown ();for ( future<integer> future : list) {try {_log.info ("result=" + future.get ());} catch (exception e) {_log.error (e, e);}}}
Use unbounded queues as queues in the thread pool package com.jzli.threadpool;import java.util.linkedlist;import java.util.list; import java.util.concurrent.future;import java.util.concurrent.linkedblockingqueue;import java.util.concurrent.threadpoolexecutor;import java.util.concurrent.timeunit;import org.apache.log4j.logger;import com.jzli.threadpool.task.sleeptask;/** * The test uses the Linkedblockingqueue unbounded queue as the task receive queue when . test Result: a thread that does not create a new thread, the maximum number of threads does not work, and always has only the number of core threads. * Test Conclusion: It is not recommended to use the * * * Official document Description: unbounded queue. Using unbounded queues (for example, linkedblockingqueue with no predefined capacity) causes all corePoolSize * threads to be busy waiting in the queue. This way, the created thread will not exceed corepoolsize. (therefore the value of the,maximumpoolsize * is not valid.) When each task is completely independent of other tasks, that is, when task execution does not affect each other, it is appropriate to use a unbounded queue, for example, in a Web * page server. This queueing can be used to handle transient burst requests, which allow the possibility of an increase in the number of lines that are allowed to occur when the command reaches an average of more than the queue can handle. * * @author lijinzhao * */public class threadpoolexecutortestwithlinkedblockingqueue {private&Nbsp;static final logger _log = logger.getlogger ( Threadpoolexecutortestwithlinkedblockingqueue.class);p Ublic static void main (String[] args ) throws exception {new threadpoolexecutortestwithlinkedblockingqueue (). Test ();} Private int coresize = 10;private int maxsize = 100;public void test () throws Exception {ThreadPoolExecutor threadPool = null;// When using bounded queues, the thread pool creates new threads to perform tasks when the number of tasks is greater than the number of core threads plus the queue size, but at this point the handlers that reject the task also reject a portion of the task threadpool = new Threadpoolexecutor (coresize, maxsize, 30l,timeunit.seconds, new linkedblockingqueue< Runnable> (), New threadpoolexecutor.discardoldestpolicy ()); List<future<integer>> list = new linkedlist<future<integer>> (); for (int i = 1; i <= 500; i++) {list.add (ThreadPool.submit (new sleeptasK (i), i));} Int count = 0;do {count = threadpool.getactivecount (); _log.info ( Threadpool.getpoolsize ()); TimeUnit.SECONDS.sleep (1);} while (count > 0);for (future<integer> future : list) { Try {_log.info ("result=" + future.get ());} catch (exception e) {_log.error (e, e);}} _log.info (Threadpool.getpoolsize ()); TimeUnit.SECONDS.sleep, _log.info ("====================================="); _log.info (threadpool.getpoolsize ());list = new linkedlist<future<integer>> ();for (int i = 1; i <= 100; i++) {list.add (Threadpool.submit (New sleeptask (i), i));} Count = 0;do {count = threadpool.getactivecount (); TimeUnit.SECONDS.sleep (1);} while (count > 0); _log.info (Threadpool.getpoolsize ()); Threadpool.shutdown (); _log.info ( Threadpool.getpoolsize ()); for (future<integer> future : list) {try {_log.info ("result=" + Future.get ());} catch (exception e) {_log.error (e, e);}}}
Use a bounded queue as a queue in the thread pool
package com.jzli.threadpool;import java.util.linkedlist;import java.util.list;import java.util.concurrent.future;import java.util.concurrent.linkedblockingqueue;import java.util.concurrent.threadpoolexecutor;import java.util.concurrent.timeunit;import org.apache.log4j.logger;import com.jzli.threadpool.task.sleeptask;/** * Test using Arrayblockingqueue or Linkedblockingqueue bounded queue as task receive queue test result: * 1. When the number of tasks is greater than the number of core threads plus the queue for large hours * The thread pool creates new threads to perform tasks, but when the maximum number of threads is insufficient, the thread pool uses the Reject task handler to reject a portion of the task because of the maximum thread count and the size of the queue. * 2. When the number of queues is large enough, a new thread is not created and only the core thread is used to perform the task, in which case the task execution is slow . * 3. When the number of tasks is greater than the sum of the number of core threads in the queue, the thread pool creates new threads to perform tasks and, if the maximum number of threads is sufficient, can keep all tasks quickly and correctly completed. * Test Conclusion: recommended, recommended to set the maximum number of threads is large enough * (3000), the queue size is a certain number (100), the number of core threads is a certain number (100), the save time is 1800 seconds, It is also found that the naming rules for creating threads seem to have been added up. * * Official documentation Description: bounded queues. When using a limited maximumPoolSizes , bounded queues (such as * arrayblockingqueue) help prevent resource exhaustion, but may be difficult to adjust and control * . The queue size and maximum pool size may need to be compromised:With large queues and small pools, you can minimize CPU * usage, operating system resources, and context switching overhead, but can lead to artificially reduced throughput. If tasks are frequently blocked (for example, if they are I/O * boundaries), then the system may schedule more threads than you permit. Using small queues typically requires a large pool size,cpu * usage is high, but may encounter unacceptable scheduling overhead, which can also degrade throughput. * * @author lijinzhao * */public class threadpoolexecutortestwitharrayblockingqueue {private static final logger _log = logger.getlogger (threadpoolexecutortestwitharrayblockingqueue.class);p ublic static void Main (String[] args) throws Exception {new Threadpoolexecutortestwitharrayblockingqueue (). Test ();} Private int coresize = 100;private int maxsize = 3000;private int queuesize = 100;public void test () throws exception { threadpoolexecutor threadpool = null;// when using bounded queues, the thread pool creates new threads to perform tasks when the number of tasks is greater than the number of core threads plus the queue size. However, the process of rejecting a task will also reject a portion of the task Threadpool = new thrEadpoolexecutor (coresize, maxsize, 30l,timeunit.seconds, new linkedblockingqueue< Runnable> (Queuesize), New threadpoolexecutor.callerrunspolicy ()); List<future<integer>> list = new linkedlist<future<integer>> (); for (int i = 1; i <= 500; i++) {list.add (ThreadPool.submit (new sleeptask (i), i));} Int count = 0;do {count = threadpool.getactivecount (); TimeUnit.SECONDS.sleep (1);} while (count > 0);for (future<integer> future : list) { Try {_log.info ("result=" + future.get ());} catch (exception e) {_log.error (e, e);}} Gets the current number of threads in the pool _log.info (Threadpool.getpoolsize ()); TimeUnit.SECONDS.sleep, _log.info ("=====================================");// gets the current number of threads in the pool _log.info ( Threadpool.getpoolsize ()); list = new linkedlist<future≪integer>> ();for (int i = 1; i <= 100; i++) {list.add ( Threadpool.submit (New sleeptask (i), i));} Count = 0;do {count = threadpool.getactivecount (); TimeUnit.SECONDS.sleep (1);} while (count > 0);// Gets the current number of threads in the pool _log.info (Threadpool.getpoolsize ()); Threadpool.shutdown ();for (future<integer> future : list) {try {_log.info ( "result=" + future.get ()); catch (exception e) {_log.error (e, e);}}}
Package Com.jzli.threadpool.task;import java.util.concurrent.timeunit;import org.apache.log4j.logger;/** * Print serial number, And sleep for a second * * @author Lijinzhao * */public class Sleeptask implements Runnable {private static final Logger _log = logger.g Etlogger (sleeptask.class);p rivate int i;public sleeptask (int i) {super (); this.i = i;} @Overridepublic void Run () {try {_log.info (i); TimeUnit.SECONDS.sleep (1);} catch (Interruptedexception e) {_log.error (E, E);}}}
Test conclusion: It is recommended to use a bounded queue as a queue in the thread pool, set the number of core threads to a medium-sized number (100), set the maximum number of threads to a larger number (3000), set the queue capacity to a medium-sized number (1000), and the thread hold time to a relatively long time ( 1800 seconds) to prevent threads from being repeatedly created and destroyed.
This article is from the "Litt58 Technology World" blog, so be sure to keep this source http://litt58.blog.51cto.com/4917855/1604098
Java threadpoolexecutor thread pool usage instructions