"As a Java developer, have you ever encountered the problem of too many threads concurrency? When there are too many threads, it will lead to waste of resources, degraded application performance, and even thread deadlock. So, is there an effective way Manage threads efficiently and avoid these problems? The answer is yes, that is the thread pool. In this article, we will explore the mysteries of the thread pool from the perspective of Java, gain an in-depth understanding of the advantages of the thread pool, and learn how to use the thread pool to achieve multiple Thread concurrency."
How is the thread pool created?
There are mainly two types of methods for creating thread pools in JAVA. One is the method provided by the Executors factory class, which provides 4 different thread pools for use. The other is custom creation through the ThreadPoolExecutor class.
Executors factory class
// Five thread pools: // ExecutorService threadPool = null; // threadPool = Executors.newCachedThreadPool();//A buffered thread pool, the number of threads is controlled by the JVM // threadPool = Executors.newFixedThreadPool(3);//fixed size thread pool // threadPool = Executors.newScheduledThreadPool(2); // Has delay and timing functions // threadPool = Executors.newSingleThreadExecutor();//Single-threaded thread pool, only one thread is working // threadPool = new ThreadPoolExecutor();//The default thread pool has many controllable parameters private static void createCachedThreadPool() { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; executorService.execute(() -> { // Get thread name, default format: pool-1-thread-1 System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index); // wait 2 seconds sleep(2000); }); } }
ThreadPoolExecutor class
ThreadPoolExecutor provides a construction method, you need to set specific parameters yourself, which is more flexible
public ThreadPoolExecutor(int corePoolSize, // number of core threads int maximumPoolSize, // max worker threads long keepAliveTime, // Survival time, how long the thread will last when there is no task to execute before it will be terminated. TimeUnit unit, // time unit BlockingQueue<Runnable> workQueue, // work queue ThreadFactory threadFactory, // The thread factory is mainly used to create threads, defaulting to normal priority, non-daemon threads. RejectedExecutionHandler handler // Rejection strategy, when a new thread is created so that the number of threads is greater than the maximum thread, it will be executed ) { // omit... }
The main parameters of the thread pool
- corePoolSize number of core threads
The number of core threads, the number of threads that are always alive in the thread pool. - BlockingQueue work queue
workQueue = new ArrayBlockingQueue<>(5);//Array-based first-in-first-out queue, bounded
workQueue = new LinkedBlockingQueue<>();//First-in-first-out queue based on linked list, unbounded
workQueue = new SynchronousQueue<>();//unbuffered waiting queue, unbounded threadFactory thread factory
It is used to set the factory for creating threads, which can be created for each thread factory. Thread settings with more meaningful names. Use the ThreadFactoryBuilder provided by the open source framework guava to quickly set meaningful names for the threads in the thread pool. The code is as follows:new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
- handler
Reject policy, the policy when rejecting the task, 4 options, the default is AbortPolicy.
parameter | describe |
---|---|
AbortPolicy | reject and throw an exception |
CallerRunsPolicy | Only use the thread of the caller to run the task |
DiscardOldestPolicy | A task at the head (oldest) of the queue is discarded and the current task is executed. |
DiscardPolicy | Abandon the current task. |
RejectedExecutionHandler rejected = null; rejected = new ThreadPoolExecutor.AbortPolicy();//By default, when the queue is full and the task is lost, an exception is thrown rejected = new ThreadPoolExecutor.DiscardPolicy();//It is not abnormal to lose tasks when the queue is full rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//Delete the task that entered the queue first, and then try to join the queue rejected = new ThreadPoolExecutor.CallerRunsPolicy();//If adding to the thread pool fails, the main thread will execute it by itself
The execution process of the thread pool?
- The main thread submits tasks to the thread pool. If the current number of threads is less than the number of core threads, create a new thread to execute the task. If not, go to the next step.
- At this time, the core thread is full, and then judge whether the number of threads stored in the work queue is full, if not, put it into the work queue, if not, go to the next step.
- At this time, the work queue is full, and then check whether the current number of threads is equal to the maximum number of threads, if yes, implement the rejection strategy, if not, create a new thread, and execute the task.
Configure the maximum number of threads in the thread pool
- cpu-intensive maximumPoolSize = n*cpu + 1
- io-intensive maximumPoolSize = 2 * n * cpu
Closing the thread pool
A thread pool can be shut down by calling the thread pool's shutdown or shutdownNow method.
The same point: traverse all worker threads, and then interrupt the threads
The difference: After shutdown is called, no new tasks will be accepted, but it will wait for the running threads and stop the threads that are not executing tasks.
When shutdownNow is called, it attempts to stop the thread that is running or suspends the task.
It's not easy to be original, please give me a thumbs up and go!
This article is written by mdnice Multi-platform publishing