当前位置:网站首页>Elegant custom ThreadPoolExecutor thread pool

Elegant custom ThreadPoolExecutor thread pool

2022-06-24 21:52:00 Jingling cat

summary

java It is often necessary to Use multithreading to handle some business , very Not recommended Use Inherit Thread perhaps Realization Runnable Interface The way to Create thread , like that Creating and destroying threads is bound to consume resources 、 Thread context switching problem . meanwhile Creating too many threads can also lead to the risk of resource exhaustion , This is the time It is reasonable to introduce thread pool , Facilitate the management of thread tasks .

java The related classes related to thread pool in jdk 1.5 At the beginning java.util.concurrent In bag , Several core classes and interfaces involved include :Executor、Executors、ExecutorService、ThreadPoolExecutor、FutureTask、Callable、Runnable etc.

JDK Automatically create thread pool Several methods of are encapsulated in Executors Tool class in :

newFixedThreadPool

new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())

Set up corePoolSize=maxPoolSize,keepAliveTime=0( This parameter has no effect at this time ), Unbounded queue , Mission Sure Unlimited placement , When Too many requests ( The task processing speed cannot keep up with the task submission speed, resulting in request accumulation ) It may cause excessive memory consumption or directly cause OOM abnormal .

newSingleThreadExector

new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), var0)

basic Same as newFixedThreadPool, however Set the number of threads to 1, Single thread , Disadvantages and newFixedThreadPool Agreement

newCachedThreadPool

new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue())

corePoolSize=0,maxPoolSize For a large number , Synchronous handover queue , in other words Do not maintain resident threads ( Core thread ), Each time a request is made, a new thread is created directly to handle the task , also Do not use queue buffering , Meeting Automatically reclaim redundant threads , because take maxPoolSize Set to Integer.MAX_VALUE, When there are many requests, it is possible to create too many threads , Lead to exhaustion of resources OOM

newScheduledThreadPool

new ThreadPoolExecutor(var1, 2147483647, 0L, TimeUnit.NANOSECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue())

Support Execute periodically at a fixed time , Pay attention to the Using a delay queue , The disadvantages are the same as newCachedThreadPool Agreement

So the above says to use Executors The thread pool created by the tool class has hidden dangers , So how to use it to avoid this hidden danger ? What is the most elegant way to use a thread pool ?

How is it reasonable for a production environment to configure its own thread pool ? We need to take the right medicine , Create your own thread factory class , Set key parameters flexibly .

ThreadPoolExecutor class

want Custom thread pool , Need to use ThreadPoolExecutor class

ThreadPoolExecutor Construction method of class ,7 Parameters

public ThreadPoolExecutor(int coreSize,int maxSize,long KeepAliveTime,TimeUnit unit,BlockingQueue queue,ThreadFactory factory,RejectedExectionHandler handler)
corePoolSize:  Number of core threads , It is also the number of resident threads in the thread pool 
			    When the thread pool is initialized, there are no threads by default , When the task comes, it starts to create a thread to execute the task 

maximumPoolSize:  Maximum number of threads , Some non core threads may be added to the number of core threads 
				   It should be noted that only when  workQueue  The queue is not created until it is full   More than  corePoolSize  The thread of 
				  ( The total number of threads in the thread pool does not exceed maxPoolSize)

keepAliveTime:  Non core thread   Of   free time   exceed  keepAliveTime  Will be   Automatically terminate recycling 
			     Pay attention to when  corePoolSize=maxPoolSize  when ,keepAliveTime  Parameters don't work ( Because there are no non core threads )
			    
unit: keepAliveTime  Time unit of 

workQueue:  The queue used to hold the task , Can be unbounded 、 bounded 、 Synchronous handover is one of three queue types 
			 When the number of worker threads in the pool   Greater than  corePoolSize  when , At this time, the new task will be put in the queue 
			
threadFactory:  Create a factory class for threads , By default  Executors.defaultThreadFactory(), You can also use  guava  Library ThreadFactoryBuilder  To create 

handler:  The thread pool cannot continue to receive tasks ( The queue is full and the number of threads reached  maximunPoolSize ) Saturation strategy at 
		   Values are AbortPolicyCallerRunsPolicyDiscardOldestPolicyDiscardPolicy

Thread pool configuration related

Setting the thread pool size

Be clear about our needs Computationally intensive still IO intensive

Computationally intensive

Applications need to be A lot of CPU Computing resources , In multicore CPU Time , We want to Let every one CPU The core is involved in the calculation , take CPU Take full advantage of the performance , This is not a waste of server configuration , If Running a single threaded program on a very good server configuration would be a huge waste . For computationally intensive applications , Entirely on CPU To work , So in order for it to fully play its advantages , Avoid excessive thread context switching , The ideal solution is :

 Number of threads  = CPU  Check the number  + 1, You can also set it to CPU Check the number *2, But also look at  JDK  Version and  CPU  To configure ( Server's CPU Have hyper-threading )

 General Settings   

CPU * 2  that will do 

IO intensive

Most of the current development is WEB application , involves A lot of network traffic , More Than This , With the database , The interaction with the cache is also involved IO, Once occurred IO, The thread will be in a waiting state , When IO end , When the data is ready , The thread will continue execution .

about IO Intensive application , We can Set more threads in the thread pool , So that we can Waiting for the IO During this period of time , Threads can do other things , Improve the efficiency of concurrent processing . So the amount of data in this thread pool can be set arbitrarily ? Of course not , Please do remember , Thread context switching comes at a cost . At present, a set of formulas is summarized , about IO Intensive application :

 Number of threads  = CPU The core number /(1- Block coefficient )  The blocking coefficient is usually zero 0.8~0.9 Between , Can also take 0.8 perhaps 0.9.

To paraphrase formula , about Dual core CPU Come on , It's more The ideal number of threads is 20, Of course, none of this is absolute , It needs to be adjusted according to the actual situation and the actual business :final int poolSize = (int)(cpuCore/(1-0.9))

Thread pool related parameter configuration

One 、 A certain Do not select configuration items without upper limit .

That's why Not recommended Executors Method to create a thread in .

for example ,Executors.newCachedThreadPool The settings and Setting of unbounded queue Because of some unexpected circumstances , A system exception will occur in the thread pool , A condition that causes a thread explosion or a task queue to swell , Running out of memory leads to system crashes and exceptions

 It is recommended to use a custom thread pool to avoid this problem , This is also the first principle in using the thread pool specification !

Two 、 Set the number of threads appropriately 、 And thread idle recovery time

according to Set the specific task execution cycle and time , Avoid frequent recycling and creation , Although we use thread pools for Improve system performance and throughput , But you also have to think about the stability of the system , Otherwise it would be very troublesome to have unexpected problems !

3、 ... and 、 According to the actual scenario , Choose a rejection strategy that works for you

Make compensation , Don't mess with JDK Automatic compensation mechanism supported Try to use a custom rejection policy to cover the cost

Four 、 Thread pool rejection policy , Custom rejection policies can be implemented RejectedExecutionHandler Interface

JDK The default rejection strategy is as follows :

AbortPolicy: Throwing an exception directly prevents the system from working properly .
CallerRunsPolicy: As long as the thread pool is not closed , The policy is directly in the caller thread , Run the currently discarded task .
DiscardOldestPolicy: Discard the oldest request , Try to commit the current task again .
DiscardPolicy: Discard unmanageable tasks , Do not give any treatment .

utilize Hook

utilize Hook, leave Thread pool execution trace

ThreadPoolExecutor Provides protected Type of hook method that can be overridden , Allows the user to do something before and after the task is executed . We can use it to achieve, for example initialization ThreadLocal、 Collect statistics 、 Such as logging operations . This kind of Hook Such as beforeExecute and afterExecute. in addition One more Hook Can be used to allow the user to insert logic when the task is completed , Such as rerminated

If hook Method execution failed , be The execution of the internal worker thread will fail or be interrupted

We can use beforeExecute and afterExecute Come on Record some running conditions before and after the thread , You can also directly record the state after the completion of the run ELK Isolog system .

Close thread pool

When The thread pool is no longer referenced also The number of worker threads is 0 When , The thread pool will be terminated . We can call shutdown To manually terminate the thread pool . If we Forget to call shutdown, For thread resources to be freed , We You can also use keepAliveTime and allowCoreThreadTimeOut To achieve the goal !

Of course , A safe way It's using virtual machine Runtime.getRuntime().addShutdownHook Method , Manually call the thread pool closure method

Things that can be optimized

Set the threads in the thread pool to Daemon

In general , After closing the thread pool , The thread pool will End the thread by itself . but For some of their own camouflage or direct new Thread() This thread of , Will still block the process from shutting down

according to ,java Process shutdown determination method , When There is only Daemon Threads when , The process will shut down normally . therefore , Suggest these All non primary threads are set to daemon, That is, process shutdown will not be blocked

Correct naming Thread

When using thread pools , Usually Accept ThreadFactory object , Come on Controls how to create thread. stay java Self contained ExecutorService when , If This parameter is not set , will Use default DefaultThreadFactory. The effect is , You will be in the stack list , See a bunch of pool-x-thread-y, In actual use jstack when , It is impossible to see the group to which each of these threads belongs , And the specific role .

Discard recurring tasks that are no longer available

In general , Use java Self contained ScheduledThreadPoolExecutor, call scheduleAtFixedRate And scheduleWithFixedDelay All will Set the task to periodic (period). stay Thread pool shutdown when , These tasks can be discarded directly ( By default ).

But if Use schedule When adding long-term tasks , Thread pool will Because it is not a periodic task, the corresponding thread will not be closed

Such as spring In the system TriggerTask( Include CronTask), To carry out Scheduled tasks , They all end up being adopt schedule To achieve scheduling , And in When a single task is completed , Again schedule To perform the next task . This approach would be considered not period. therefore , When using this scheduling method , Although when the container is closed , Yes shutdown Method , But corresponding to the bottom ScheduledExecutorService It still won't shut down successfully ( Although all States have been set ). The end result is , You will see one that is already in shutdown Thread pool for state , But the thread is still running ( Status as wait Mission ) The situation of

To solve this problem ,java Provide an additional setting parameter executeExistingDelayedTasksAfterShutdown, This value defaults to true, namely shutdown after , Still carry out . It can be done by When defining a thread pool, set it to false, That is, after the thread pool is closed , Don't run these deferred tasks anymore

原网站

版权声明
本文为[Jingling cat]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/175/202206241450296673.html