Elegant java thread pool

Introduction
thread pool surely we have used, JDK also comes with a number of Executors thread pool. But do not know if you have ever wondered, how is the most elegant way to thread pool used it? Production environment to how to configure their own thread pool is reasonable it?
Today weekend, just time to sum up my thought 'elegant', any questions welcome to correct me.

Thread Pool usage rules
to better use the thread pool, so be sure to follow a few rules:

Set the number of thread size
thread pool configuration parameters
using the embedded Hook your behavior
close the thread pool
thread pool configuration related to
the thread pool size setting
This is actually a test center interview, the interviewer will ask you a lot of thread pool size to coreSize examine your understanding for the thread pool.
First, specific to this problem, we have to clear our needs are compute-intensive or IO-intensive, and only learned about this number, we can better to set the thread pool limit.

1, compute-intensive :
As the name suggests is the application needs a lot of computing resources CPU, multi-core CPU era, we have to let each CPU core are involved in the calculation, the CPU performance fully utilized, this is not considered a waste of server configuration, if on a very good server configuration is also running a single-threaded program that will be just as significant waste. For compute-intensive applications, to work entirely on the number of core CPU, so in order to make it fully play out the advantages, avoid excessive thread context switching, the ideal solution is:

The number of threads = number +1 CPU core can also be set to the number of CPU cores * 2, but it depends on the JDK version, and CPU configurations (server's CPU Hyper-Threading).

General Settings CPU * 2 can be.

2, IO-intensive
most developers we are doing all WEB application involves a large amount of network traffic, not only that, with the database, interaction between the cache and also involves IO, IO occurs once, the thread will be in a wait state when the end of the IO, data is ready, the thread will continue. Therefore, can be found here for IO intensive applications, we can set the number of multi-threaded some of the thread pool, so that we can make at this time to wait for IO, the thread can do other things, to improve the efficiency of concurrent processing. Then the amount of data that is not thread pool can easily set it? Of course not, be sure to remember that thread context switch comes at a price. Currently summed up a formula for IO intensive applications:
threads = CPU cores / (l blockage factor) between the blockage factor is generally 0.8 to 0.9, 0.8 or 0.9 may be taken.
Apply the formula for a dual-core CPU, it's the ideal number of threads is 20, of course, is not absolute, needs to be adjusted according to the actual situation and the real business: final int poolSize = (int) (cpuCore / (1-0.9) )

You mentioned in one sentence for obstruction factor, "Programming Concurrency on the JVM Mastering" namely "Java Virtual Machine Concurrent Programming":

For the blocking factor, we can first try to guess, or use some tender analysis tools or java.lang.management API to determine the time ratio of the time and CPU-intensive tasks on the system spends thread / IO operation consumption.

Thread pool configuration parameters
when it comes to this, we just need to keep in mind that you must not choose no upper limit to the configuration items .
This is why the method is not recommended for use in creating a thread Executors.
For example, Executors.newCachedThreadPool settings and unbounded queue settings because of some unexpected situation, the system thread pool will be abnormal, leading to surge threads situation or task queue continues to expand, leading to memory exhaustion system crashes and exceptions. We recommend using a custom thread pool to avoid this problem, which is the overriding principle in the use of standardized thread pool! Safe right now, do not over-confident!
Executors can look at four methods to create a thread pool:

//使用无界队列
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

// infinite number of thread pool
public static ExecutorService newCachedThreadPool () {
        return new new the ThreadPoolExecutor (0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new new SynchronousQueue <the Runnable> ());
    }
else is no longer listed, everyone free to review the source code.

Second, a reasonable set number of threads, and thread idle recovery time, depending on the task execution cycle and time to be set, to avoid frequent recovery and creation, although we aim to use the thread pool is to improve system performance and throughput, but also consider the stability of the system, otherwise unexpected problems arise will be trouble!
Third, according to the actual scene, choose suitable for their rejection policy. To compensate, do not mess with automatic compensation mechanism JDK support! Try using custom tactics refuse to carry out reveal all the details!
Fourth, the thread pool deny policy, custom policy may refuse to implement RejectedExecutionHandler interface.
JDK comes with the denial strategy is as follows:
AbortPolicy: Direct thrown prevent the system from working properly.
CallerRunsPolicy: As long as the thread pool is not closed, the policy directly in the caller's thread, run the current task is discarded.
DiscardOldestPolicy: discard the oldest request, try to submit the current job again.
DiscardPolicy: discard can not handle the task, not given any treatment.

Hook the use of
the use of Hook, leaving the thread pool to perform the track:
ThreadPoolExecutor provides a hook method protected type can be overridden, allowing the user to do something before the task is executed after the execution. We can use it to achieve such initialization ThreadLocal, gather statistics, such as logging and other operations. BeforeExecute such as Hook and afterExecute. There is also a Hook can be used when the task is finished executing logic allows the user to insert, as rerminated.
If the hook method fails, the implementation of the internal thread will fail or be interrupted.

We can use beforeExecute and afterExecute to record some operating conditions before the thread before and after, you can also run directly to the state after the completion of the recording to the ELK log and other systems.

Close the thread pool
contents when the thread pool is not cited and the number of worker threads is 0, the thread pool will be terminated. We can also call the shutdown manually terminate the thread pool. If we forget to call shutdown, in order to allow the thread resources are released, we can also use keepAliveTime and allowCoreThreadTimeOut to achieve their goals!
Of course, the prudent approach is to use a virtual machine Runtime.getRuntime (). AddShutdownHook method, hand to call the close method of the thread pool !

We can implement a custom thread pool by ThreadPoolExecutor

ThreadPoolTaskExecutor is spring core pack, and is in the JDK ThreadPoolExecutor JUC. ThreadPoolTaskExecutor is ThreadPoolExecutor process is encapsulated.

 

Finally, attach the items I produce usage :

ThreadPoolTaskConfig
package com.zcckj.common.db.config.thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;


@Configuration
@Slf4j
public class ThreadPoolTaskConfig {

	@Value("${task.core_pool_size}")
	private Integer corePoolSize;
	@Value("${task.max_pool_size}")
	private Integer maxPoolSize;
	@Value("${task.queue_capacity}")
	private Integer queueCapacity;
	@Value("${task.keep_alive_seconds}")
	private Integer keepAliveSeconds;


	@Bean(name="taskExecutor")
	public ThreadPoolTaskExecutor taskExecutor(){
		ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
		//线程池维护线程的最少数量
		poolTaskExecutor.setCorePoolSize(corePoolSize);
		//线程池维护线程的最大数量
		poolTaskExecutor.setMaxPoolSize(maxPoolSize);
		//线程池所使用的缓冲队列
		poolTaskExecutor.setQueueCapacity(queueCapacity);
		//线程池维护线程所允许的空闲时间
		poolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
		poolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
		return poolTaskExecutor;
	}

}

use


    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    …………

    taskExecutor.execute(() -> dosomething……);

 

This article refers to self: https://blog.csdn.net/u012881584/article/details/85221635

Published 33 original articles · won praise 6 · views 10000 +

Guess you like

Origin blog.csdn.net/kuangni5808/article/details/102541443