This article is to share the knowledge about multithreading in Java, which is my notes and summary in the learning process. This content was tested in a JDK1.8 environment.
Let’s share:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
We know that THE CPU executes code sequentially, so by nature a computer with a single CPU will not execute multiple tasks at the same time. But in reality, when we use computers, we can chat on wechat while listening to music. So how does that work? In fact, operating system multitasking is to allow the CPU to perform multiple tasks alternately.
Take, for example, a classroom with three groups of grade one, grade two, and grade three at the same time, and the teacher spends one minute teaching grade one, one minute teaching grade two, one minute teaching grade three, and so on in turn, it looks like teaching three grades at once.
Similarly, when we use computers, we listen to music while chatting on wechat. The CPU lets wechat execute for 0.001 seconds and the music player for 0.001 seconds. In our view, the CPU is performing multiple tasks at the same time.
1.1 Concepts of Programs, Processes, and Threads Program: A static pile of code that is an executable file stored on a disk or other data storage device.
Process: An executable program instance that runs in memory
Thread: A thread is an entity of a process and is the basic unit of CPU scheduling and dispatch.
Look at these concepts are not very abstract, look at very uncomfortable, so let me use examples to explain these concepts.
It says that when we use a computer, we can chat on wechat while listening to music. So what’s the whole process of running this software?
If we want to use wechat to chat, most of us just double click the “wechat” shortcut on the desktop, and double click this shortcut to open a. Exe file, which is a program, please see the following picture:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
Double-click the.exe file and load the executable into memory so that the CPU can read it easily. The executable instance is a process. See the picture below:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
When we use wechat, wechat will do a lot of things, such as loading wechat UI interface, displaying wechat friend list and chatting with friends, which can be regarded as a single thread in the process of wechat.
Let me summarize the process with a picture:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
Given the concept of threads, is there any question as to how threads are created? With that in mind, let’s look at how threads are created in Java.
Java.lang.Thread represents threads. Any Thread is an instance of Thread (a subclass).
2.2 Common method construction methods
Function is introduced
Thread()
Constructs objects without arguments
Thread(String name)
Constructs the object from the name specified by the argument
Thread(Runnable target)
Constructs an object from the reference specified by the argument, where Runnable is an interface type
Thread(Runnable target, String name)
An object is constructed by specifying a reference and name as parameters
Members of the method
Function is introduced
run()
1. Construct a thread object using a Runnable reference, which ends up calling version 2 in the interface when called. The thread object is constructed without a Runnable reference and does nothing when the method is called
start()
Used to start a thread, the Java virtual machine automatically calls the run method of that thread
A custom class inherits the Thread class and overrides the run method as needed. It then calls the start method on the object that created the class in the main class, thus starting a Thread.
Example code is as follows:
// Create a custom SubThreadRun class that inherits Thread as an alternate Thread class
public class SubThreadRun extends Thread {
@override public void run() {// Print integer values from 1 to 20 for (int I = 0; i < 20 ; I ++) {system.out.println ("SubThreadRun: "+ I); }}Copy the code
}
// Create the thread in the main method and start it
public class SubThreadRunTest {
public static void main(String[] args) { //1. Thread t1 = new SubThreadRun(); // To start a thread, the Java virtual machine automatically calls the run method t1.start() in that thread; }Copy the code
}
Output result:
In SubThreadRun: 0 in SubThreadRun: 2...... SubThreadRun: 19Copy the code
Here you will have the following question, look at the example code:
public class SubThreadRunTest {
public static void main(String[] args) { //1. Thread t1 = new SubThreadRun(); // Call the run method to test t1.run(); }Copy the code
}
Output result:
0 in the SubThreadRun thread: 1...... SubThreadRun: 19Copy the code
Instead of calling start, we call run and find the same result. What is the difference between the two methods?
We also add a number to print 1-20 in the main method, and then use the run method and start method respectively to test, the example code is as follows:
// Use the run method to test
public class SubThreadRunTest {
public static void main(String[] args) { //1. Thread t1 = new SubThreadRun(); //2. Call the run method to test t1.run(); // Print integer values from 1 to 20 for (int I = 0; i < 20 ; I + +) {System. Out. Println (" -- -- -- -- -- mian - method: "+ I); }}Copy the code
}
Output result:
0 in the SubThreadRun thread: 1...... In the SubThreadRun thread: 19 -----mian----- : 0 -----mian----- : 1...... -----mian----- -----mian----- : 19Copy the code
// Use the start method to test
public class SubThreadRunTest {
public static void main(String[] args) { //1. Thread t1 = new SubThreadRun(); // To start a thread, the Java virtual machine automatically calls the run method t1.start() in that thread; // Print integer values from 1 to 20 for (int I = 0; i < 20 ; I + +) {System. Out. Println (" -- -- -- -- -- mian - method: "+ I); }}Copy the code
}
Output result:
In the SubThreadRun thread: 0 -----mian----- : 0 in the SubThreadRun thread: 1 in the SubThreadRun thread: 2 -----mian----- : 1...... SubThreadRun thread: 19 -----mian----- method: 19Copy the code
From the above example we can see:
When a run test is called, it is essentially a call to a normal member method, so the execution flow is that the code in the run method is executed before it can proceed.
When you call the start test, you start another thread, plus the thread executing the main method. There are two threads running at the same time, so the output is staggered.
We’ve already learned the first way to create threads. Are there any drawbacks to this way of creating threads? If the SubThreadRun class already inherits from a parent class, then we would use the class as a custom Thread class. To implement the SubThreadRun class using methods that inherit from Thread would violate the Java concept of non-multiple inheritance. So the second creation method avoids this problem.
Implement the Runnable interface and rewrite the run method. Create an object of the class as an argument to construct an object of type Thread. Then call the start method with the object of type Thread.
Example code is as follows:
// Create a custom class SubRunnableRun that implements the Runnable interface
public class SubRunnableRun implements Runnable {
@Override public void run() { for (int i = 0; i < 20 ; I ++) {system.out.println ("SubRunnableRun thread: "+ I); }}Copy the code
}
// Create the thread in the main method and start it
public class SunRunnableRunTest {
public static void main(String[] args) { //1. SubRunnableRun SRR = new SubRunnableRun(); Thread t1 = new Thread(SRR); //3. Call the start method t1.start() with an object of type Thread; For (int I = 0; i < 20 ; I + +) {System. Out. Println (" -- -- -- -- -- mian - method: "+ I); }}Copy the code
}
Output result:
0 -----mian----- : 0 in the SubRunnableRun thread: 1 in the SubRunnableRun thread: 2 -----mian----- : 1...... SubRunnableRun thread: 19 -----mian----- method: 19Copy the code
Is there a question at this point?
I instantiated Thread in the main method of the SunRunnableRunTest class. Why does this Thread call the run method of SubRunnableRun class that implements the Runnable interface instead of the run method of Thread class?
To solve this problem, we will enter the Thread class to look at the source code, the source code call process is as follows:
SunRunnableRunTest (Thread); SunRunnableRunTest (Thread);
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
The constructor calls init and passes the target argument as an argument.
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
3. After going to the corresponding init method, the init method continues to call another overloaded init method, passing the target argument as an argument.
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
4. In the init method, target is assigned to the member variable target.
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
5. Call target as long as the target member variable is present.
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
By looking at the source code, we can see why the Thread class we created calls the Run method of the Runnable class.
Each of the above methods requires creating a separate class that inherits the Thread class or implements the Runnable interface and overwrites the Run method. Anonymous inner classes allow custom threads to be created without creating separate classes.
Example code is as follows:
public class ThreadNoNameTest {
Public static void main(String[] args) {public static void main(String[] args) {public static void main(String[] args) {public static void main(String[] args) {public static void main(String[] args) {public static void main(String[] args) { Thread t1 = new Thread() {@override public void run() {Override public void run() { System.out.println(" create Thread from Thread class...") ); }}; t1.start(); Runnable ra = new Runnable() {@override public void run() {Override public void run() { System.out.println(" Implementation Runnable interface implementation thread...") ); }}; Thread t2 = new Thread(ra); t2.start(); }Copy the code
}
These two ways of creating threads using anonymous inner classes continue to simplify code, especially the way of creating threads using the Runnable interface, which can be simplified using Lambda expressions.
Example code is as follows:
public class ThreadNoNameTest {
public static void main(String[] args) { //1. New Thread() {@override public void run() {system.out.println (" Thread ") {@override public void run() {system.out.println (" Thread "); ); } }.start(); New Thread(new Runnable() {@override public void run() {@override public void run() { System.out.println(" Runnable thread ") ); } }).start(); //2-1. For interfaces with anonymous internal creation threads, we can continue to use lambda expressions for simplification. //Java8 starts to support lambda expressions :(parameter list) -> {method body; } Runnable ra = () -> system.out.println (" Lambda expressions simplify implementation Runnable interface way implementation thread..." ); new Thread(ra).start(); New Thread(() -> system.out.println ("lambda expressions simplify implementation of Runnable interface implementation of threads...") )).start(); }Copy the code
}
From the above examples, we have seen that there are two ways to create a thread. However, the problem with these two ways is that the run method does not return a value, so if we want to give a result after the thread terminates, Then you need to implement the Callable interface to create threads.
(1) Callable interface
Starting from the Java 5 new create a thread in the third way to implement Java. Util. Concurrent. Callable interface.
The common methods are as follows:
Members of the method
Function is introduced
V call()
Evaluates the result, and if it cannot, throws an exception
We know that the only way to start a Thread is to create a Thread class and call the start method. If we want to call the Call method in the Callable interface, we need to use the FutureTask class.
(2) FutureTask class
Java. Util. Concurrent. FutureTask class implements the RunnableFuture interface, RunnableFuture interface is a complex of Runnable and Future, a Future, FutureTask can perform asynchronous computation, You can check whether the asynchronous program is finished, and you can start and cancel the program, and get the final execution result of the program, and can also be used to get the return result after calling the method.
The common methods are as follows:
A constructor
Function is introduced
FutureTask(Callable callable)
Create a FutureTask that will execute the given Callable at runtime
Members of the method
Function is introduced
V get()
Gets the result of the call method calculation
The FutureTask class is a subclass of Runnable, so the FutureTask class can be used as an argument to Thread. This way we can create a thread and call the Call method in the Callable interface.
Example code is as follows:
public class ThreadCallableTest implements Callable {
@override public Object call() throws Exception {// Calculate the sum between 1 and 10000 and print int sum = 0. for (int i = 0; i <= 10000; i ++) { sum += i; } system.out. println("call result: "+ sum); return sum; } public static void main(String[] args) { ThreadCallableTest tct = new ThreadCallableTest(); FutureTask ft = new FutureTask(tct); Thread t1 = new Thread(ft); t1.start(); Object ob = null; try { ob = ft.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } system.out.println (" result in main: "+ ob); }Copy the code
}
Output result:
Result in the call method: 50005000Copy the code
Result in main: 50005000
2.3.5 Creating a Thread Pool
Before talking about thread pool, let’s tell a story. A boss runs a restaurant, but this restaurant is very strange. Every time a customer comes, the boss will hire a new chef to cook. Under this way of doing business, the boss would be too busy hiring chefs to do anything.
As for the above story, the restaurant owners in real life are not so stupid. They all hire several chefs to wait in the kitchen before opening a restaurant. When customers come, they cook and serve dishes directly.
Let’s take a look at where thread pools come from: for example, in server programming, if a new worker thread is assigned to each client, and when the worker thread finishes communicating with the client, the thread is destroyed, this requires frequent creation and destruction of worker threads. If there are too many clients accessing the server, the performance of the server can be severely affected.
So how do we free up servers? By the way, just like the restaurant owner mentioned above, build a back kitchen and let the chef wait. In contrast to the server, a thread pool is created, and the thread waits for the client to connect. When the client finishes communicating, the server does not close the thread, but returns to the thread and waits. This frees up the server.
Thread pool concept:
When a server receives a client request, it takes a spare thread from the thread pool to serve it. Instead of closing the thread, it puts it back into the thread pool.
Related classes and methods:
There are seven ways to create a thread pool, but generally they fall into two categories:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
Executors is a factory class for tools and thread pools. Use the following methods to create and return different types of thread pools:
The return value
methods
Function is introduced
static ExecutorService
newFixedThreadPool(int nThreads)
Create a thread pool of a fixed size, and if the number of tasks exceeds the number of threads, the excess portion will wait in the queue
static ExecutorService
newCachedThreadPool()
Create a thread pool that can create new threads as needed. If the number of tasks at a time is greater than the number of threads, new threads can be created based on the number of tasks. If the task is completed, the thread is recycled after a period of caching.
static ExecutorService
newSingleThreadExecutor()
Create a thread pool with a single number of threads to ensure first-in, first-out execution order
static ScheduledExecutorService
newScheduledThreadPool(int corePoolSize)
Create a thread pool that can execute deferred tasks
static ScheduledExecutorService
newSingleThreadScheduledExecutor()
Create a single-threaded thread pool that can execute deferred tasks
static ExecutorService
newWorkStealingPool()
Create a thread pool for preemptive execution (task execution order not determined)
ThreadPoolExecutor creates a thread pool using a constructor, which can be set to a maximum of seven parameters. The constructor is as follows:
A constructor
Function is introduced
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
Create a thread pool the most primitive way
The ExecutorService interface is a real thread pool interface. The main implementation class is ThreadPoolExecutor. The common methods are as follows:
Method statement
Function is introduced
void execute(Runnable command)
Performs tasks and commands, usually used to perform Runnable
Future submit(Callable task)
Performs tasks and commands, typically for Callable execution
void shutdown()
Start orderly shutdown
Example code:
Create a thread pool using the newFixedThreadPool method
public class FixedThreadPool {
Public static void main (String [] args) {/ / create contains two threads thread pool ExecutorService threadPool = Executors. NewFixedThreadPool (2); Runnable Runnable = new Runnable() {@override public void run() {system.out.println (" thread :" + Thread.currentthread ().getName() + "Task executed!" ); }}; Threadpool.execute (runnable); threadPool.execute(runnable); threadPool.execute(runnable); threadPool.execute(runnable); }Copy the code
}
Output result:
Thread: Pool-1-thread-2 executed the task!
Thread: Pool-1-thread-1 executed the task!
Thread: Pool-1-thread-2 executed the task!
Thread: Pool-1-thread-1 executed the task!
As you can see from the results, these four tasks are executed by two fixed threads in the thread pool, and the thread pool does not create new threads to execute the task.
2. Use the newCachedThreadPool method to create a thread pool
public class cachedThreadPool {
public static void main(String[] args) { //1. Create a thread pool ExecutorService ExecutorService = Executors. NewCachedThreadPool (); Runnable Runnable = new Runnable() {@override public void run() {system.out.println (" thread :" +) Thread.currentthread ().getName() + "Task executed!" ); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } } }; For (int I = 0; i < 100; i ++) { executorService.execute(runnable); }}Copy the code
}
Output result:
Thread: Pool-1-thread-1 executed the task!
Thread: Pool-1-thread-4 executed the task!
Thread: Pool-1-thread-3 executed the task!
Thread: Pool-1-thread-2 executed the task!
Thread: Pool-1-thread-5 executed the task!
Thread: Pool-1-thread-7 Executed the task!
Thread: Pool-1-thread-6 Executed the task!
Thread: Pool-1-thread-8 Executed the task!
Thread: Pool-1-thread-9 Executed the task!
Thread: Pool-1-thread-10 Executed the task!
As you can see from the results, the thread pool creates the corresponding number of threads based on the number of tasks.
3. Use the newSingleThreadExecutor method to create a thread pool
public class singleThreadExecutor {
Public static void main (String [] args) {/ / create a thread pool ExecutorService ExecutorService = Executors. NewSingleThreadExecutor (); For (int I = 0; i < 10; i ++) { final int task = i + 1; Executorservice.execute (()->{system.out.println (" Thread :" + thread.currentThread ().getName() +" execute "+ task +" task!" ); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}); }}Copy the code
}
Output result:
Thread: Pool-1-thread-1 performs task 1!
Thread :pool-1-thread-1 performs task 2!
Thread :pool-1-thread-1 performs task 3!
Thread :pool-1-thread-1 performs task 4!
Thread :pool-1-thread-1 performs task 5!
Thread: Pool-1-thread-1 performed task 6!
Thread: Pool-1-thread-1 performed task 7!
Thread: Pool-1-thread-1 performed task 8!
Thread: Pool-1-thread-1 performed task 9!
Thread :pool-1-thread-1 performed task 10!
As you can see from the results, the thread created by this method can guarantee the order of task execution.
4. Use the newScheduledThreadPool method to create a thread pool
public class ScheduledThreadPool {
Public static void main(String[] args) {// Create a thread pool containing 2 threads ScheduledExecutorService ScheduledExecutorService = Executors.newScheduledThreadPool(2); SimpleDateFormat formatter = new SimpleDateFormat(" YYYY-MM-DD HH: MM :ss"); Date startTime = new Date(); String start = formatter.format(startTime); System.out.println(" create task time :" + start); Runnable Runnable = new Runnable() {@override public void run() {Date endTime = new Date(); String end = formatter.format(endTime); System.out.println(" Thread :" + thread.currentThread ().getName() + "); }}; // execute the task (parameter: runnable- task to execute, 2- delay time from now on, timeunit.seconds - delay TimeUnit) for(int I = 0; i < 2; i ++) { scheduledExecutorService.schedule(runnable,2, TimeUnit.SECONDS); }}Copy the code
}
Output result:
Create task time :2021-04-19 19:26:18
Thread :pool-1-thread-1 The task execution time is 2021-04-19 19:26:20
Thread: Pool-1-thread-2 The task execution time is 2021-04-19 19:26:20
As you can see from the results, the thread pool created by this method can allocate existing threads to perform some tasks that need to be deferred.
5. NewSingleThreadScheduledExecutor method is used to create a thread pool
public class SingleThreadScheduledExecutor {
Public static void main(String[] args) {// Create a thread pool ScheduledExecutorService ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); // Create task Date startTime = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String start = formatter.format(startTime); System.out.println(" create task time :" + start); Runnable runnable = new Runnable() { @Override public void run() { Date endTime = new Date(); String end = formatter.format(endTime); System.out.println(" Thread :" + thread.currentThread ().getName() + "); }}; For (int I = 0; i < 2; i ++) { scheduledExecutorService.schedule(runnable,2, TimeUnit.SECONDS); }}Copy the code
}
Output result:
Create task time :2021-04-19 19:51:58
Thread :pool-1-thread-1 The task execution time is 2021-04-19 19:52:00
Thread :pool-1-thread-1 The task execution time is 2021-04-19 19:52:00
As you can see from the results, this method creates a thread pool with only one thread to perform tasks that need to be deferred.
6. Create a thread pool using the newWorkStealingPool method
public class newWorkStealingPool {
Public static void main (String [] args) {/ / create a thread pool ExecutorService ExecutorService = Executors. NewWorkStealingPool (); For (int I = 0; i < 4; i ++) { final int task = i + 1; Executorservice.execute (()->{system.out.println (" Thread :" + thread.currentThread ().getName() +" execute "+ task +" task!" ); }); } // Make sure the task is executed while (! executorService.isTerminated()) { } }Copy the code
}
Output result:
The forkJoinpool-1-worker-9 thread performed the first task!
The forkJoinpool-1-worker-4 thread performed the fourth task!
Thread :ForkJoinPool-1-worker-11 performs task 3!
Forkjoinpool-1 worker-2 executes task 2!
As you can see, this method creates a thread pool with enough threads to maintain the appropriate level of parallelism, and the task is preemptively executed. (Task execution order is uncertain)
Before writing the sample code, LET me give you a life example (going to the bank) : Describe the business scenario: there are four Windows in the bank, only two are open today, and there are three places in the waiting area. As shown below:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
If there are less than or equal to five people dealing with the bank at the same time, then it is just right that two people deal with the bank first and the others wait in the waiting area. As shown in the figure below
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
If the number of customers is six, the bank opens window number three. As shown below:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
If the number of simultaneous transactions is seven, the bank will open window 4 for transactions. As shown below:
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
If more than seven people are doing business at the same time, the manager of the bank lobby will tell the people in the back that the branch is full and please go to another branch.
Java multithreading knowledge summary! After 20 times of testing and combing, netizen: too comprehensive
Now let’s look at our ThreadPoolExecutor constructor, which can set up to seven parameters:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
Copy the code
Parameter Description:
CorePoolSize: number of core threads, threads that always exist in the thread pool (corresponding to the banking business model: open window from the start)
MaximumPoolSize: the maximum number of threads that can be created in a thread pool, and several threads other than the core threads will be created when the pool’s task queue is full (for banking model: all Windows)
KeepAliveTime: The maximum thread lifetime. When there is no work for a long time, the thread pool destroys some threads and keeps the core thread
Timeunit.days: DAYS timeunit.hours: HOURS timeunit.minutes: MINUTES timeunit.seconds: MILLISECONDS: MILLISECONDS timeunit. MICROSECONDS: MICROSECONDS timeunit. NANOSECONDS: NANOSECONDS
WorkQueue: wait queue, used to store tasks waiting in the thread pool (corresponding to the banking business model: wait area) ArrayBlockingQueue: a bounded blocking queue supported by arrays. LinkedBlockingQueue: A bounded blocking queue of linked lists. SynchronousQueue: This blocking queue does not store tasks but submits them directly to threads, resulting in the execution of submitted tasks by idle threads if available, or by creating a new thread otherwise. DelayQueue: an unbounded blocking queue that uses a priority queue to support delayed fetching of elements, from which elements can be extracted only when the delay expires. Taobao order business: after placing an order, if the payment is not made within 30 minutes, the order will be automatically cancelled. LinkedTransferQueue: An unbounded blocking queue consisting of a linked list structure. LinkedBlockingDeque: A bidirectional blocking queue consisting of a linked list structure.
ThreadFactory: threadFactory, used to create threads.
Handler: The policy used to reject processing of a task that exceeds the acceptable scope of the thread pool. ThreadPoolExecutor. AbortPolicy: When a task is added to the thread pool is refused, it will throw RejectedExecutionException exception (defaults to using this strategy) ThreadPoolExecutor. CallerRunsPolicy: When a task is added to the thread pool is rejected, is called the place of the current thread pool threads to carry out the tasks of rejection ThreadPoolExecutor. DiscardOldestPolicy: When a task is added to the thread pool is rejected, will discard the old task in task queue is the first to join the queue, and then add the new tasks in ThreadPoolExecutor. DiscardPolicy: if the task is rejected, this directly to ignore or abandon the task
When the number of tasks is less than or equal to the sum of the number of core threads + the number of waiting queues:
public class ThreadPoolExecutorTest {
Public static void main(String[] args) {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 100) TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); Runnable Runnable = new Runnable() {@override public void run() { System.out.println(thread.currentThread ().getName() + "==> Execute task "); }}; For (int I = 0; i < 5; i++) { threadPool.execute(runnable); } // close the threadPool threadpool.shutdown (); }Copy the code
}
Output result:
Pool-1 thread-2==> Execute tasks
Pool-1 thread-1==> Execute tasks
Pool-1 thread-2==> Execute tasks
Pool-1 thread-1==> Execute tasks
Pool-1 thread-2==> Execute tasks
As you can see from the results, there are only two core threads executing tasks.
When the number of tasks is greater than the total number of core threads + the number of wait queues, but less than or equal to the maximum number of threads:
public class ThreadPoolExecutorTest {
Public static void main(String[] args) {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 100) TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); Runnable Runnable = new Runnable() {@override public void run() { System.out.println(thread.currentThread ().getName() + "==> Execute task "); }}; For (int I = 0; i < 7; i++) { threadPool.execute(runnable); } // close the threadPool threadpool.shutdown (); }Copy the code
}
Output result:
Pool-1 thread-1==> Execute tasks
Pool-1 thread-4==> Execute tasks
Pool-1 thread-2==> Execute tasks
Pool-1 thread-2==> Execute tasks
Pool-1 thread-3==> Execute tasks
Pool-1 thread-4==> Execute tasks
Pool-1 thread-1==> Execute tasks
As you can see from the results, the maximum thread is started to execute the task.
When the number of tasks is greater than the maximum number of threads:
public class ThreadPoolExecutorTest {
Public static void main(String[] args) {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 100) TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); Runnable Runnable = new Runnable() {@override public void run() { System.out.println(thread.currentThread ().getName() + "==> Execute task "); }}; For (int I = 0; i < 8; i++) { threadPool.execute(runnable); } // close the threadPool threadpool.shutdown (); }Copy the code
}
Output result:
Exception in thread “main” java.util.concurrent.RejectedExecutionException: Task com.zck.task18.ThreadPool.ThreadPoolExecutorTest$1@7f31245a rejected from java.util.concurrent.ThreadPoolExecutor@6d6f6e28[Running, pool size = 4, active threads = 0, queued tasks = 0, completed tasks = 7]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.zck.task18.ThreadPool.ThreadPoolExecutorTest.main(ThreadPoolExecutorTest.java:25)
Pool-1 thread-1==> Execute tasks
Pool-1 thread-4==> Execute tasks
Pool-1 thread-4==> Execute tasks
Pool-1 thread-4==> Execute tasks
Pool-1 thread-2==> Execute tasks
Pool-1 thread-3==> Execute tasks
Pool-1 thread-1==> Execute tasks
As you can see from the result, the task is larger than the maximum number of threads, and an exception is thrown directly using a reject policy.
This article introduces three ways to create threads:
The custom class inherits the Thread class and overwrites the run method
Custom classes implement the Runnable interface and override the run method creation
Implement Callable interface creation
There are seven ways to create thread pools:
Create a thread pool using the newFixedThreadPool method
Create a thread pool using the newCachedThreadPool method
Create a thread pool using the newSingleThreadExecutor method
Create a thread pool using the newScheduledThreadPool method
NewSingleThreadScheduledExecutor method is used to create a thread pool
Create a thread pool using the newWorkStealingPool method
Create a thread pool using ThreadPoolExecutor
The above is today’s thread knowledge sharing, thank you for watching, but also welcome everyone to exchange and discuss, if the article is not correct, I hope you forgive me.
If the content is helpful, please give me a thumbs-up and support. Your support is the motivation for my creation.