Article catalog
- 1, Asynchronous thread pool
- 1. Thread status introduction
- 2. Thread status - Exercise 1
- 3. Thread status - Exercise 2
- 4. Thread status - exercise 3
- 5. Thread pool - Fundamentals
- 6. Thread pool - Executors default thread pool
- 7. Thread pool - Executors creates a thread pool with a specified upper limit
- 8. Thread pool - ThreadPoolExecutor
- 9. Thread pool - parameter details
- 10. Thread pool - non default task rejection policy
1, Asynchronous thread pool
1. Thread status introduction
When a thread is created and started, it neither enters the execution State as soon as it is started, nor is it always in the execution State. Thread objects have different states in different periods. The thread State in Java is defined in Java lang.Thread. In the State enumeration class, the source code of the State enumeration class is as follows:
public class Thread { public enum State { /* newly build */ NEW , /* Operational status */ RUNNABLE , /* Blocking state */ BLOCKED , /* Infinite waiting state */ WAITING , /* Timed waiting */ TIMED_WAITING , /* termination */ TERMINATED; } // Gets the status of the current thread public State getState() { return jdk.internal.misc.VM.toThreadState(threadStatus); } }
Through the source code, we can see that there are six thread states in Java. The meaning of each thread state is as follows
Thread state | Specific meaning |
---|---|
NEW | The state of a thread that has not been started. It is also called initial state and start state. The thread was just created but not started. The start method has not been called. MyThread t = new MyThread() has only thread images and no thread characteristics. |
RUNNABLE | When we call the start method of the thread object, the thread object enters the RUNNABLE state. At this time, a thread is really created in the JVM process. Once the thread is started, it is not executed immediately. Whether the thread runs or not depends on the command and CPU scheduling. Then we call this intermediate state RUNNABLE, that is, it is qualified for execution, but it is not really executed, but waiting for the degree of CPU. |
BLOCKED | When a thread attempts to obtain an object lock and the object lock is held by other threads, the thread enters the Blocked state; When the thread holds a lock, the thread becomes Runnable. |
WAITING | The state of a waiting thread. It is also called waiting state. There are two reasons for thread waiting: calling object Wait() and join() methods. A thread in a waiting state is waiting for another thread to perform a specific operation. For example, a thread waiting for wait() is waiting for another thread to call notify() or notifyAll(); A thread waiting for join () is waiting for another thread to end. |
TIMED_WAITING | The state of a thread waiting for a limited time. It is also called time limited waiting state. There are three reasons for the thread time limited wait state: thread sleep(long),Object.wait(long),join(long). |
TERMINATED | The state of a fully running thread. It is also called termination state and end state |
The transition of each state is shown in the following figure:

2. Thread status - Exercise 1
Purpose: this case mainly demonstrates time_ State transition of waiting.
**Requirements: * * write a piece of code to display the status of a thread in turn: New - > runnable - > time_ WAITING -> RUNNABLE -> TERMINATED
In order to simplify our development, we use anonymous inner classes combined with lambda expressions to use multithreading.
code implementation
public class ThreadStateDemo01 { public static void main(String[] args) throws InterruptedException { //Define an internal thread Thread thread = new Thread(() -> { System.out.println("2.implement thread.start()After that, the status of the thread:" + Thread.currentThread().getState()); try { //Sleep for 100ms Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4.implement Thread.sleep(long)After completion, the status of the thread:" + Thread.currentThread().getState()); }); //Gets the status before start() System.out.println("1.adopt new Initialize a thread, but not yet start()Status of the thread before:" + thread.getState()); //Start thread thread.start(); //Sleep for 50 ms Thread.sleep(50); //Because thread1 needs to sleep for 100 milliseconds, the thread is in the sleep state in the 50th Ms System.out.println("3.implement Thread.sleep(long)Status of the thread when:" + thread.getState()); //thread1 and main threads actively sleep for 150 milliseconds, so the thread has already been executed in the 150th milliseconds Thread.sleep(100); System.out.println("5.After the thread is executed, the status of the thread:" + thread.getState() + "\n"); } }
console output
1.adopt new Initialize a thread, but not yet start()Status of the thread before: NEW 2.implement thread.start()After that, the status of the thread: RUNNABLE 3.implement Thread.sleep(long)Status of the thread when: TIMED_WAITING 4.implement Thread.sleep(long)After completion, the status of the thread: RUNNABLE 5.After the thread is executed, the status of the thread: TERMINATED
3. Thread status - Exercise 2
Purpose: this case mainly demonstrates the state transition of WAITING.
**Requirements: * * write a piece of code to display the status of a thread in turn: New - > runnable - > waiting - > runnable - > terminated
Code implementation:
public class ThreadStateDemo02 { public static void main(String[] args) throws InterruptedException { //Define an object to lock and unlock Object obj = new Object(); //Define an internal thread Thread thread1 = new Thread(() -> { System.out.println("2.implement thread.start()After that, the status of the thread:" + Thread.currentThread().getState()); synchronized (obj) { try { //thread1 needs to sleep for 100 milliseconds Thread.sleep(100); //After thread 1100 milliseconds, the obj object is released through the wait() method obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("4.cover object.notify()After the method wakes up, the status of the thread:" + Thread.currentThread().getState()); }); //Gets the status before start() System.out.println("1.adopt new Initialize a thread, but not yet start()Status of the thread before:" + thread1.getState()); //Start thread thread1.start(); //main thread sleeps for 150 milliseconds Thread.sleep(150); //Because thread1 enters the wait state in the 100th millisecond, its state can certainly be obtained in the 150th second System.out.println("3.implement object.wait()Status of the thread when:" + thread1.getState()); //Declare another thread to unlock new Thread(() -> { synchronized (obj) { //Wake up waiting threads obj.notify(); } }).start(); //The main thread sleeps for 10 milliseconds and waits for thread1 thread to wake up Thread.sleep(10); //Gets the state after the end of thread1 run System.out.println("5.After the thread is executed, the status of the thread:" + thread1.getState() + "\n"); } }
Console output results
1.adopt new Initialize a thread, but not yet start()Status of the thread before: NEW 2.implement thread.start()After that, the status of the thread: RUNNABLE 3.implement object.wait()Status of the thread when: WAITING 4.cover object.notify()After the method wakes up, the status of the thread: RUNNABLE 5.After the thread is executed, the status of the thread: TERMINATED
4. Thread status - exercise 3
Purpose: this case mainly demonstrates the state transition of BLOCKED.
**Requirements: * * write a piece of code to display the status of a thread in turn: New - > runnable - > blocked - > runnable - > terminated
public class ThreadStateDemo03 { public static void main(String[] args) throws InterruptedException { //Define an object to lock and unlock Object obj2 = new Object(); //Define a thread that preempts the lock of obj2 object first new Thread(() -> { synchronized (obj2) { try { Thread.sleep(100); //The first thread holds the lock for 100 milliseconds obj2.wait(); //Then, the wait() method is used to wait and release the object lock of obj2 } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); //Define the target thread to obtain the lock waiting for obj2 Thread thread = new Thread(() -> { System.out.println("2.implement thread.start()After that, the status of the thread:" + Thread.currentThread().getState()); synchronized (obj2) { try { Thread.sleep(100); //thread3 holds the object lock for 100 milliseconds obj2.notify(); //Then wake up all the threads waiting on ojb2 through the notify() method to continue to perform subsequent operations } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("4.Status of thread after blocking:" + Thread.currentThread().getState()); }); //Gets the status before start() System.out.println("1.adopt new Initialize a thread, but not yet thread.start()Status of the thread before:" + thread.getState()); //Start thread thread.start(); //Wait 100 milliseconds first Thread.sleep(50); //It takes at least 100 milliseconds for the first thread to release the lock, so at the 50th MS, the thread is blocking waiting for obj's object lock System.out.println("3.When blocked due to waiting for a lock, the status of the thread:" + thread.getState()); //Wait another 300 milliseconds Thread.sleep(300); //The execution time of the two threads plus the 50 milliseconds waiting before is 250 milliseconds in total, so all threads have been executed in the 300th Ms System.out.println("5.After the thread is executed, the status of the thread:" + thread.getState()); } }
Console output results
1.adopt new Initialize a thread, but not yet thread.start()Status of the thread before: NEW 2.implement thread.start()After that, the status of the thread: RUNNABLE 3.When blocked due to waiting for a lock, the status of the thread: BLOCKED 4.Status of thread after blocking: RUNNABLE 5.After the thread is executed, the status of the thread: TERMINATED
5. Thread pool - Fundamentals
summary:
When it comes to pools, you should think of pools. A pool is a container in which a lot of water is stored. So what is a thread pool? Thread pool can also be seen as a pool in which many threads are stored.
Significance of thread pool:
The cost of creating a thread in the system is relatively high, because it involves interaction with the operating system. When a large number of threads with very short lifetime need to be created in the program, the resource consumption of the system caused by frequent thread creation and destruction may be greater than that of business processing
To control the consumption of resources, it is a bit of "discarding the basics and discarding the end". In this case, in order to improve performance, we can use thread pool. When the thread pool is started, a large number of idle threads will be created. When we submit tasks to the thread pool, the thread pool will
A thread is started to perform the task. After the task is executed, the thread does not die, but returns to the thread pool again, which is called idle state. Wait for the execution of the next task.
Design idea of thread pool:
- Prepare a task container
- Start multiple (2) consumer threads at once
- At first, the task container was empty, so all threads were wait ing
- Until an external thread throws a "task" into the task container, a consumer thread will be awakened
- The consumer thread takes out the "task" and executes the task. After execution, it continues to wait for the next task
6. Thread pool - Executors default thread pool
Overview: JDK also implements the thread pool. In real enterprise development, we rarely customize the thread pool, but use the thread pool built in JDK.
We can use the static methods provided in Executors to create thread pools
static ExecutorService newCachedThreadPool() creates a default thread pool static newFixedThreadPool(int nThreads) creates a thread pool with a specified maximum number of threads
Code implementation:
package com.itheima.mythreadpool; //static ExecutorService newCachedThreadPool() creates a default thread pool //static newFixedThreadPool(int nThreads) Create a thread pool that specifies the maximum number of threads import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyThreadPoolDemo { public static void main(String[] args) throws InterruptedException { //1. Create a default thread pool object The pool is empty by default By default, it can accommodate up to the maximum value of int type ExecutorService executorService = Executors.newCachedThreadPool(); //Executors --- can help us create thread pool objects //ExecutorService --- can help us control the thread pool executorService.submit(()->{ System.out.println(Thread.currentThread().getName() + "In execution"); }); //Thread.sleep(2000); executorService.submit(()->{ System.out.println(Thread.currentThread().getName() + "In execution"); }); executorService.shutdown(); } }
7. Thread pool - Executors creates a thread pool with a specified upper limit
Use the static methods provided in Executors to create a thread pool
static ExecutorService newFixedThreadPool(int nThreads): creates a thread pool with a specified maximum number of threads
Code implementation:
package com.itheima.mythreadpool; //static ExecutorService newFixedThreadPool(int nThreads) //Create a thread pool that specifies the maximum number of threads import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class MyThreadPoolDemo2 { public static void main(String[] args) { //The parameter is not the initial value, but the maximum value ExecutorService executorService = Executors.newFixedThreadPool(10); ThreadPoolExecutor pool = (ThreadPoolExecutor) executorService; System.out.println(pool.getPoolSize());//0 executorService.submit(()->{ System.out.println(Thread.currentThread().getName() + "In execution"); }); executorService.submit(()->{ System.out.println(Thread.currentThread().getName() + "In execution"); }); System.out.println(pool.getPoolSize());//2 // executorService.shutdown(); } }
8. Thread pool - ThreadPoolExecutor
To create a thread pool object:
ThreadPoolExecutor ThreadPoolExecutor = new ThreadPoolExecutor (number of core threads, maximum number of threads, maximum lifetime of idle threads, task queue, creation of thread factory, rejection policy of task);
Code implementation:
package com.itheima.mythreadpool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class MyThreadPoolDemo3 { // Parameter 1: number of core threads // Parameter 2: maximum number of threads // Parameter 3: maximum idle thread lifetime // Parameter 4: time unit // Parameter 5: task queue // Parameter 6: create thread factory // Parameter 7: task rejection policy public static void main(String[] args) { ThreadPoolExecutor pool = new ThreadPoolExecutor(2,5,2,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); pool.shutdown(); } }
9. Thread pool - parameter details

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) corePoolSize: The maximum value of core thread cannot be less than 0 maximumPoolSize: The maximum number of threads cannot be less than or equal to 0, maximumPoolSize >= corePoolSize keepAliveTime: Maximum idle thread lifetime,Cannot be less than 0 unit: Time unit workQueue: Task queue, cannot be empty null threadFactory: Create thread factory,Cannot be null handler: Task rejection policy,Cannot be null
10. Thread pool - non default task rejection policy
RejectedExecutionHandler is a task rejection policy interface provided by jdk. There are four subclasses below it.
ThreadPoolExecutor.AbortPolicy: Discard task and throw RejectedExecutionException Abnormal. Is the default policy. ThreadPoolExecutor.DiscardPolicy: Discarding the task without throwing an exception is not recommended. ThreadPoolExecutor.DiscardOldestPolicy: Discard the longest waiting task in the queue, and then add the current task to the queue. ThreadPoolExecutor.CallerRunsPolicy: To invoke a task run()Method bypasses the thread pool and executes directly.
Note: specify the number of tasks that can be executed by the thread pool = queue capacity + maximum number of threads
Case demonstration 1: demonstrate ThreadPoolExecutor Abortpolicy task processing policy
public class ThreadPoolExecutorDemo01 { public static void main(String[] args) { /** * The number of core threads is 1, the maximum number of thread pools is 3, the capacity of task container is 1, and the maximum lifetime of idle threads is 20s */ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.AbortPolicy()) ; // Five tasks are submitted, and the thread pool can handle up to four tasks. When we use the AbortPolicy task processing policy, an exception will be thrown for(int x = 0 ; x < 5 ; x++) { threadPoolExecutor.submit(() -> { System.out.println(Thread.currentThread().getName() + "---->> Performed the task"); }); } } }
Console output results
pool-1-thread-1---->> Performed the task pool-1-thread-3---->> Performed the task pool-1-thread-2---->> Performed the task pool-1-thread-3---->> Performed the task
The console reports an error. Only four tasks have been executed, and one task has been discarded
Case demonstration 2: demonstrate ThreadPoolExecutor Discardpolicy task processing policy
public class ThreadPoolExecutorDemo02 { public static void main(String[] args) { /** * The number of core threads is 1, the maximum number of thread pools is 3, the capacity of task container is 1, and the maximum lifetime of idle threads is 20s */ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardPolicy()) ; // Five tasks are submitted, and the thread pool can process up to four tasks. When we use the task processing policy of DiscardPolicy, the console will not report an error for(int x = 0 ; x < 5 ; x++) { threadPoolExecutor.submit(() -> { System.out.println(Thread.currentThread().getName() + "---->> Performed the task"); }); } } }
Console output results
pool-1-thread-1---->> Performed the task pool-1-thread-1---->> Performed the task pool-1-thread-3---->> Performed the task pool-1-thread-2---->> Performed the task
The console did not report an error. Only four tasks were executed, and one task was discarded
Demo case: poolthread.3 Discardoldestpolicy task processing policy
public class ThreadPoolExecutorDemo02 { public static void main(String[] args) { /** * The number of core threads is 1, the maximum number of thread pools is 3, the capacity of task container is 1, and the maximum lifetime of idle threads is 20s */ ThreadPoolExecutor threadPoolExecutor; threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardOldestPolicy()); // Submit 5 tasks for(int x = 0 ; x < 5 ; x++) { // Define a variable to specify the currently executed task; This variable needs to be modified by final final int y = x ; threadPoolExecutor.submit(() -> { System.out.println(Thread.currentThread().getName() + "---->> Performed the task" + y); }); } } }
Console output results
pool-1-thread-2---->> Task 2 was performed pool-1-thread-1---->> Task 0 executed pool-1-thread-3---->> Task 3 was performed pool-1-thread-1---->> Task 4 was performed
Task 1 was discarded because it waited the longest in the process pool.
Case demonstration 4: demonstrate ThreadPoolExecutor Callerrunspolicy task processing policy
public class ThreadPoolExecutorDemo04 { public static void main(String[] args) { /** * The number of core threads is 1, the maximum number of thread pools is 3, the capacity of task container is 1, and the maximum lifetime of idle threads is 20s */ ThreadPoolExecutor threadPoolExecutor; threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.CallerRunsPolicy()); // Submit 5 tasks for(int x = 0 ; x < 5 ; x++) { threadPoolExecutor.submit(() -> { System.out.println(Thread.currentThread().getName() + "---->> Performed the task"); }); } } }
Console output results
pool-1-thread-1---->> Performed the task pool-1-thread-3---->> Performed the task pool-1-thread-2---->> Performed the task pool-1-thread-1---->> Performed the task main---->> Performed the task
From the console output, we can see that the secondary policy does not execute the task through the thread in the thread pool, but directly calls the run() method of the task to bypass the thread pool.