background
I believe that many people in work will use thread pool, but the definition of thread pool is a relatively complicated process, because there are as many as 7 thread pool constructors alone, and the definition of each parameter is not simple basic data structure directly passed in
So for those who don’t have the experience, use the default thread pool provided by the JDK to build the tool Executors
Executors do provide some thread pool constructs for easy use, but all of them are unbounded queues, and too many tasks may cause OOM. Alibaba specification also prohibits the use of Executors to construct thread pools
Although some of Ali’s own open source middleware does not comply with the specification, that does not prevent it from being a good specification
Obtain the task exception log
Note that the default UncaughtExceptionHandler policy for thread pool errors during task execution is printed to the console
This is just a small problem, the problem is more troublesome method is to use a thread pool submit submit tasks in an exception occurs will not print exception information, only when the results of retrieval task will print error, when some people don’t need to get the task results will use the submit to submit this way, the task will lead to abnormal also don’t know, This is a bad one, like this
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(() -> {
int i = 1 / 0;
});
Copy the code
We don’t know what happened. Look at the source code
The thread executing the task is encapsulated as a RunnableFuture object. Let’s look at the Run method of the RunnableFuture object
The exception thrown is placed into the Outcome object, which is the result of FutureTask executing the GET () method that is returned by submit()
Do not use the Submit method if you do not need to retrieve the result of the task
The number of threads in the thread pool is not set
A dynamic thread pool is a popular design in the industry. I have written before about how to implement a dynamic thread pool
Weihubeats.blog.csdn.net/article/det…
However, there is generally a formula for calculating the number of threads in a thread pool
- I/O intensive: Optimal number of threads = Number of CPU cores * [1 + (I/O time/CPU time)]
- CPU intensive: The optimal number of threads is CPU+1
The thread count setting for the thread pool needs to be resolved
Thread pool name
The default thread pool name is pool-x-thread-x. It is also very inconvenient to locate thread pool problems on our line. We need to specify the appropriate prefix for each thread pool
coded
Based on these issues, let’s optimize a thread pool builder class of our own
To solve the problem of thread pool not printing errors and thread name prefixes, we define a custom thread creation factory
ThreadFactoryImpl
public class ThreadFactoryImpl implements ThreadFactory {
private final AtomicLong threadIndex = new AtomicLong(0);
private final String threadNamePrefix;
private final boolean daemon;
public ThreadFactoryImpl(final String threadNamePrefix) {
this(threadNamePrefix, false);
}
public ThreadFactoryImpl(final String threadNamePrefix, boolean daemon) {
this.threadNamePrefix = threadNamePrefix;
this.daemon = daemon;
}
@Override
public Thread newThread(@NotNull Runnable r) {
Thread thread = new Thread(r, threadNamePrefix + this.threadIndex.incrementAndGet());
thread.setDaemon(daemon);
returnthread; }}Copy the code
Then define a thread pool utility class with associated utility methods
ThreadPoolUtil
public static ThreadFactory createThreadFactory(String threadNamePrefix, boolean daemon) {
if(threadNamePrefix ! =null) {
return new ThreadFactoryImpl(threadNamePrefix, daemon);
}
return Executors.defaultThreadFactory();
}
Copy the code
Next comes the core implementation of the custom thread pool builder utility class
ThreadPoolBuilder
public class ThreadPoolBuilder {
private static final RejectedExecutionHandler defaultRejectHandler = new ThreadPoolExecutor.AbortPolicy();
/** * Number of CPU cores */
private static final int CPU = SystemUtil.getCPU();
/**
* create io ThreadPoolExecutor
*
* @return ThreadPoolExecutor
*/
public static IOThreadPoolBuilder ioThreadPoolBuilder(a) {
return new IOThreadPoolBuilder();
}
/**
* create cpu ThreadPoolExecutor
*
* @return* /
public IOThreadPoolBuilder CPUPool(a) {
return new IOThreadPoolBuilder();
}
public static class IOThreadPoolBuilder {
private ThreadFactory threadFactory;
private RejectedExecutionHandler rejectHandler;
private int queueSize = -1;
private int maximumPoolSize = CPU;
private int keepAliveTime = 120;
private boolean daemon = false;
private String threadNamePrefix;
public int getCorePooSize(int ioTime, int cpuTime) {
return CPU + (1 + (ioTime / cpuTime));
}
public IOThreadPoolBuilder setThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
return this;
}
public IOThreadPoolBuilder setDaemon(boolean daemon) {
this.daemon = daemon;
return this;
}
public IOThreadPoolBuilder setRejectHandler(RejectedExecutionHandler rejectHandler) {
this.rejectHandler = rejectHandler;
return this;
}
public IOThreadPoolBuilder setQueueSize(int queueSize) {
this.queueSize = queueSize;
return this;
}
public IOThreadPoolBuilder setMaximumPoolSize(int maximumPoolSize) {
this.maximumPoolSize = maximumPoolSize;
return this;
}
public IOThreadPoolBuilder setKeepAliveTime(int keepAliveTime) {
this.keepAliveTime = keepAliveTime;
return this;
}
public ThreadPoolExecutor builder(int ioTime, int cpuTime) {
BlockingQueue<Runnable> queue;
if (rejectHandler == null) {
rejectHandler = defaultRejectHandler;
}
threadFactory = ThreadPoolUtil.createThreadFactory(this.threadNamePrefix, this.daemon);
queue = queueSize < 1 ? new LinkedBlockingQueue<>() : new ArrayBlockingQueue<>(queueSize);
return newThreadPoolExecutor(getCorePooSize(ioTime, cpuTime), maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, queue, threadFactory, rejectHandler); }}}Copy the code
You can impose a limit on the number of queues, or you can report an error if you do not specify it
use
ThreadPoolExecutor executor = ThreadPoolBuilder
.ioThreadPoolBuilder()
.setThreadNamePrefix("io-test")
.setMaximumPoolSize(20)
.builder(10.20);
executor.execute(() -> {
System.out.println(Thread.currentThread().getName());
int i = 1 / 0;
});
Copy the code
conclusion
As you can see, thread pool creation is still relatively complex, but we can encapsulate some thread pools that are suitable for our own development. Such as IO thread pool, CPU thread pool, CachedThreadPool, etc