Advantages of thread pool:
As long as the work of thread pool is to control the number of running threads, put the tasks in the queue during processing, and then start these tasks after the threads are created. If the number of threads exceeds the maximum number, the threads exceeding the number will queue up and wait until other threads are completed, and then take the tasks out of the queue for execution.
Its main features are: thread reuse; Control the maximum concurrent number; Manage threads.
First: reduce resource consumption. Reduce the consumption caused by thread creation and destruction by reusing the created threads.
Second: improve the response speed. When the task arrives, the task can be executed immediately without waiting for the thread to be created.
Third: improve the manageability of threads. Threads are scarce resources. If they are created without restrictions, they will not only consume system resources, but also reduce the stability of the system. Using thread pool can carry out unified allocation, tuning and monitoring.
Architecture description
The thread pool in Java is implemented through the Executor framework, which uses Executor, Executors, ExecutorService and ThreadPoolExecutor
Three methods of thread pool
1. newFixedThreadPool(int)
Good performance in executing long-term tasks. Create a thread pool with N fixed threads and a fixed number of threads
public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5); //There are five working threads in one pool, which is similar to a bank with five acceptance windows try { //Ten customers are simulated to handle banking business. At present, there are five staff in the pool for (int i = 0; i < 10; i++) { executorService.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); //Finally, the thread pool should be closed } }
//Output results pool-1-thread-1 Handle the business pool-1-thread-2 Handle the business pool-1-thread-3 Handle the business pool-1-thread-4 Handle the business pool-1-thread-5 Handle the business pool-1-thread-1 Handle the business pool-1-thread-2 Handle the business pool-1-thread-3 Handle the business pool-1-thread-4 Handle the business pool-1-thread-5 Handle the business
2. newSingleThreadExecutor()
One task, one task execution, one pool and one thread
public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); //One worker thread per pool try { //Simulate 10 customers to handle banking business for (int i = 0; i < 10; i++) { executorService.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); //Finally, the thread pool should be closed } }
//output pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business
3. newCachedThreadPool()
Many short-term asynchronous tasks are performed, and the thread pool creates new threads as needed, but reuses previously built threads when they are available. It can be expanded, and it will be strong in case of strength.
//Example 1: a single thread can complete a task quickly public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); //N worker threads in one pool try { //Simulate 10 customers to handle banking business for (int i = 0; i < 10; i++) { executorService.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); } } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); //Finally, the thread pool should be closed } }
//output pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-2 Handle the business pool-1-thread-1 Handle the business pool-1-thread-3 Handle the business pool-1-thread-6 Handle the business pool-1-thread-8 Handle the business pool-1-thread-4 Handle the business pool-1-thread-5 Handle the business pool-1-thread-7 Handle the business
//Example 2: thread pause for 1 second public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); //A worker pool N try { //Simulate 10 customers to handle banking business for (int i = 0; i < 10; i++) { executorService.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); //Finally, the thread pool should be closed } }
//Output results pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business
Underlying source code
Seven parameters of thread pool
Working principle of thread pool
- After creating the thread pool, start waiting for requests.
- When calling the execute() method to add a request task, the thread pool will make the following judgment:
2.1 if the number of running threads is less than corePoolSize, create a thread to run the task immediately;
2.2 if the number of running threads is greater than or equal to corePoolSize, put the task into the queue;
2.3 if the queue is full and the number of running threads is less than maximumPoolSize, create a non core thread to run the task immediately;
2.4 if the queue is full and the number of running threads is greater than or equal to maximumPoolSize, the thread pool will start the saturation rejection policy to execute. - When a thread completes a task, it will take a task from the queue to execute.
- When a thread has nothing to do for more than a certain time (keepAliveTime), the thread will judge:
If the number of currently running threads is greater than corePoolSize, the thread will be stopped.
Therefore, after all tasks of the thread pool are completed, it will eventually shrink to the size of corePoolSize.
Common pit
Which of the three single / fixed / variable methods of creating thread pools is more useful in work?
Answer: No, you can only use custom ones in your work
JDK in Executors has been provided to you. Why not?
Custom thread pool
public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 2, //corePoolSize 5, //maximumPoolSize 2L, //keepAliveTime TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() //Default reject policy ); try{ for (int i = 0; i < 8; i++) { threadPoolExecutor.execute(()->{ System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); } }catch(Exception e){ e.printStackTrace(); }finally{ threadPoolExecutor.shutdown(); } }
//output pool-1-thread-1 Handle the business pool-1-thread-2 Handle the business pool-1-thread-2 Handle the business pool-1-thread-2 Handle the business pool-1-thread-2 Handle the business pool-1-thread-3 Handle the business pool-1-thread-4 Handle the business pool-1-thread-5 Handle the business
Four rejection strategies of thread pool
The waiting queue is full and there are no more new tasks. At the same time, the max thread in the thread pool has reached and cannot continue to serve new tasks. At this time, we need the rejection policy mechanism to deal with this problem reasonably.
1.AbortPolicy
public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 2, 5, 2L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() //Default reject policy / / static inner class ); try{ for (int i = 0; i < 9; i++) { threadPoolExecutor.execute(()->{ System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); } }catch(Exception e){ e.printStackTrace(); }finally{ threadPoolExecutor.shutdown(); } }
//output pool-1-thread-2 Handle the business java.util.concurrent.RejectedExecutionException: Task ThreadPoolDemo$$Lambda$1/4952965@19a45b3 rejected from java.util.concurrent.ThreadPoolExecutor@99a589[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0] pool-1-thread-3 Handle the business pool-1-thread-2 Handle the business pool-1-thread-3 Handle the business pool-1-thread-1 Handle the business pool-1-thread-2 Handle the business pool-1-thread-4 Handle the business pool-1-thread-5 Handle the business at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369) at ThreadPoolDemo.main(ThreadPoolDemo.java:16)
2. CallerRunsPolicy
public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 2, 5, 2L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy() //Caller mechanism ); try{ for (int i = 0; i < 9; i++) { threadPoolExecutor.execute(()->{ System.out.println(Thread.currentThread().getName() + "\t Handle the business"); }); } }catch(Exception e){ e.printStackTrace(); }finally{ threadPoolExecutor.shutdown(); } }
//output pool-1-thread-1 Handle the business main Handle the business //"Caller run" is a kind of adjustment mechanism. This strategy will neither abandon tasks nor throw exceptions, but return some tasks to the caller, so as to reduce the traffic of new tasks. So the task is returned to the main thread of the caller main. pool-1-thread-1 Handle the business pool-1-thread-1 Handle the business pool-1-thread-2 Handle the business pool-1-thread-1 Handle the business pool-1-thread-3 Handle the business pool-1-thread-4 Handle the business pool-1-thread-5 Handle the business
3. DiscardOldestPolicy and DiscardPolicy
slightly
The above built-in rejection policies all implement the RejectedExecutionHandle interface