1. JUC overview
1.1 What is Juc
JUC, short for the Java.util.Concurrent toolkit, Java1.5 began to appear
1.2 Concepts of threads and processes
1.2.1 Processes and Threads
Process: an application that is running in the system; Once a program runs, it is a process; Process – the smallest unit of resource allocation. Thread: A basic unit of the system that allocates processor time resources, or a stream of unit execution that executes independently within a process. Thread – The smallest unit of program execution.
1.2.2 Thread Status
NEW, RUNNABLE, BLOCKED,
WAITING, (be there or be square)
TERMINATED; (end)
1.2.3 wait and sleep
- Sleep is the static method of Thread, and wait is the method of Object, which can be called by any Object instance.
- Sleep does not release the lock, nor does it need to occupy it. Wait releases the lock, but can only be called if the current thread owns the lock (i.e., synchronized).
- They can both be interrupted by the interrupted method.
1.2.4 Concurrency and parallelism
Concurrency: multiple threads are accessing the same resource at the same time, multiple threads to a point
Parallelism: multiple tasks are executed together and then summarized
1.2.5 coil
A monitor ensures that only one process is active in a pipe at a time. That is, operations defined in a pipe are called by only one process at a time (implemented by the compiler). But this does not guarantee that the processes execute in the designed order. Synchronization in the JVM is based on incoming and outgoing monitor objects. Each object has a Monitor object, which is created and destroyed along with the Java objects. When the method completes, it releases the pipe. The method holds the pipe while it executes, and no other thread can retrieve the same pipe
1.2.6 User threads and daemon threads
Daemon thread: a special thread that runs in the background, such as garbage collection. When the main thread ends, the user thread is still running, and the JVM is alive. If there are no user threads, they are daemon threads, and the JVM terminates
2. Lock the interface
2.1 Synchronized
2.1.1 Scope of Synchronized
-
Modifies a block of code, called a synchronous block, that acts on code enclosed in curly braces {} and on the object that calls the block.
-
Modify a method. The modified method is called a synchronous method. The scope of the modified method is the whole method and the object is the object that calls the method.
Although synchronized can be used to define methods, synchronized is not part of the method definition, and therefore the synchronized keyword cannot be inherited. If a method in a parent class uses the synchronized keyword and a method in a subclass overrides it, the method in the subclass is not synchronized by default, and you must explicitly add the synchronized keyword to the method in the subclass. Of course, you can also call the parent method in a subclass method, so that even though the method in the subclass is not synchronized, the subclass calls the parent's synchronized method, so that the method in the subclass is synchronized.Copy the code
-
Modify a static method that applies to the entire static method and to all objects of the class.
-
Modifies a class whose scope is the part enclosed in parentheses after synchronized, and whose main objects are all objects of the class.
2.1.2 Multithreaded programming steps
First, create a resource class, create properties and action methods
Second, create a multi-thread method to call the resource class
2.2 What is the Lock Interface
The Lock Lock implementation provides a wider range of Lock operations than can be obtained using synchronized methods and statements. They allow for more flexible structures, may have very different attributes, and may support multiple associated conditional objects. Lock offers more functionality than synchronized.
Lock differs from synchronized in the following ways:
- Lock is an interface, while synchronized is a Java keyword and synchronized is a built-in language implementation.
- Synchronized will automatically release the lock occupied by the thread when an exception occurs, so it will not lead to deadlock. UnLock (); unLock(); unLock(); unLock();
- Lock causes the thread waiting for the Lock to respond to the interrupt, whereas synchronized does not. With synchronized, the waiting thread waits forever and cannot respond to the interrupt.
- Lock can tell if a Lock has been acquired successfully, whereas synchronized cannot.
- Lock improves the efficiency of read operations by multiple threads. In terms of performance, if the resource competition is not fierce, the performance of the two is similar, but when the resource competition is very fierce (that is, there are a large number of threads competing at the same time), the performance of Lock is much better than synchronized.
2.3 Various ways to create threads
- Thread class inheritance
- Implement the Runnable interface
- Use the Callable interface
- Using thread pools
2.4 Example of using Lock to sell tickets
private final ReentrantLock lock = new ReentrantLock();
public void sale(a) {
lock.lock();
try {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + " : 卖出: " + (num --) + "The rest:"+ num); }}finally{ lock.unlock(); }}Copy the code
3. Communication between threads
sychronized
public synchronized void incr(a) throws InterruptedException {
while(number ! =0) {
this.wait();
}
number ++;
System.out.println(Thread.currentThread().getName() + "... "" + number);
this.notifyAll();
}
public synchronized void decr(a) throws InterruptedException {
while(number ! =1) {
this.wait();
}
number --;
System.out.println(Thread.currentThread().getName() + "... "" + number);
this.notifyAll();
}
Copy the code
Lock()
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void incr(a) throws InterruptedException {
lock.lock();
try {
while(number ! =0) {
condition.await();
}
number ++;
System.out.println(Thread.currentThread().getName() + "... "" + number);
condition.signalAll();
} finally{ lock.unlock(); }}public void decr(a) throws InterruptedException {
lock.lock();
try {
while(number ! =1) {
condition.await();
}
number --;
System.out.println(Thread.currentThread().getName() + "... "" + number);
condition.signalAll();
} finally{ lock.unlock(); }}Copy the code
4. Custom communication between threads
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5(int loop) throws InterruptedException {
lock.lock();
try {
while(flag ! =1) {
c1.await();
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i + "Number of rounds:" + loop);
}
flag = 2;
c2.signal();
}finally{ lock.unlock(); }}public void print10(int loop) throws InterruptedException {
lock.lock();
try {
while(flag ! =2) {
c2.await();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i + "Number of rounds:" + loop);
}
flag = 3;
c3.signal();
}finally{ lock.unlock(); }}public void print15(int loop) throws InterruptedException {
lock.lock();
try {
while(flag ! =3) {
c3.await();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i + "Number of rounds:" + loop);
}
flag = 1;
c1.signal();
}finally{ lock.unlock(); }}Copy the code
5. Thread safety between collections
5.1 The ArrayList thread is insecure
demo
List<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0.8));
System.out.println(list);
}, String.valueOf(i)).start();
}
Copy the code
Solution a Vector
List<String> list = new Vector<>();
Copy the code
Solution 2 Collections
List<String> list = Collections.synchronizedList(new ArrayList<>());
Copy the code
Solution 3 CopyOnWriteArrayList
List<String> list = new CopyOnWriteArrayList<>();
Copy the code
5.2 Hashset threads are not safe
The solution
Set set = new CopyOnWriteArraySet();
Copy the code
5.3 The HashMap thread is unsafe
The solution
Map map = new ConcurrentHashMap();
Copy the code
6. Multithreaded locks
6.1 Demonstrate eight cases of locking
class Phone {
public static synchronized void sendSMS(a) throws Exception {
TimeUnit.SECONDS.sleep(4);
System.out.println("------sendSMS");
}
public synchronized void sendEmail(a) throws Exception {
System.out.println("------sendEmail");
}
public void getHello(a) {
System.out.println("------getHello"); }}Copy the code
1 Standard access, print SMS or email first
——sendSMS
——sendEmail
2 Stop 4 seconds In the SMS method, print SMS or email first
——sendSMS
——sendEmail
3 Added the common Hello method, whether to send a short message or hello first
——getHello
——sendSMS
Now I have two mobile phones. Should I print SMS or email first
——sendEmail
——sendSMS
5 two static synchronization methods, 1 mobile phone, print SMS or email first
——sendSMS
——sendEmail 6 Two static synchronization methods, 2 mobile phones, print SMS or email first –
—–sendSMS
——sendEmail
7 one static synchronization method, one common synchronization method, and one mobile phone. SMS or email should be printed first
——sendEmail
——sendSMS
8 one static synchronization method, one common synchronization method, two mobile phones, whether to print SMS or email first
——sendEmail
——sendSMS
conclusion
For normal synchronous methods, the lock is the current instance object. For statically synchronized methods, the lock is the Class object of the current Class. For synchronized method blocks, the lock is an object configured in Synchonized parentheses
6.2 Fair lock and Unfair Lock
Unfair lock: Thread starvation is efficient
Fair lock: Sunshine, relatively high efficiency
6.3 Reentrant lock
Sychronized demo
Object o = new Object();
new Thread(() -> {
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "Outer");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "Middle");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "Inner"); }}}},"t1").start();
Copy the code
Lock the demonstration
Lock lock = new ReentrantLock();
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "Outer");
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "Middle");
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "Inner");
}finally{ lock.unlock(); }}finally{ lock.unlock(); }}finally{ lock.unlock(); }},"t1").start();
Copy the code
6.4 a deadlock
1. What is a deadlock
Two or more processes in the execution process, because of the competition for resources caused a phenomenon of waiting for each other, without external interference, they can not continue to execute
2. Cause of deadlock
- Insufficient system resources
- The process running sequence is not proper
- Misallocation of resources
Deadlock demo
4. Verify whether it is a deadlock
- JPS is similar to Ps-EF in Linux
- The JStack JVM comes with stack tracing tools
7.Callable interface &Future interface
7.1 Callable interface
- To implement Runnable, you need to implement a run() method that returns nothing, and for Callable, you need to implement a call() method that returns a result on completion
- The call method can throw an exception; run() cannot
- The Call method must be overridden to implement Callable
- Runnable cannot be replaced directly because the Thread class constructor has no Callable at all
7.2. Future Interface
When the call () method completes, the result must be stored in an object known to the main thread so that the main thread can know the result returned by the thread. To do this, you can use a Future object. There are five methods that must be overridden to implement this interface, and the important ones are listed below:
-
Public Boolean cancel (Boolean mayInterrupt)
Stop a task. If it is not started, it stops the task. If started, the task is interrupted only if mayInterrupt is trueCopy the code
-
Public Object GET () throws InterruptedException, ExecutionException
Used to get the results of the task. If the task completes, it returns the result immediately, otherwise it waits for the task to complete and then returns the resultCopy the code
-
Public Boolean isDone ()
Returns true if the task is complete, false otherwiseCopy the code
7.3, FutureTask
The Java library has a concrete FutureTask type that implements Runnable and Future and easily combines the two capabilities together. FutureTask can be created by providing a Callable to its constructor. The FutureTask object is then provided to the Thread constructor to create the Thread object. Therefore, threads are created indirectly using Callable.
Core principles
When you need to perform time-consuming operations on the main thread, but don’t want to block the main thread, you can hand those jobs off to Future objects to do in the background
- The Future object can be used to obtain the result of the calculation or execution status of the background job when the main thread needs it in the Future
- Generally, FutureTask is used for time-consuming calculations. The main thread can obtain results after completing its own tasks.
- Retrieve the results only when the calculation is complete; Block the GET method if the calculation is not complete
- Once the calculation is complete, it cannot be restarted or cancelled
- The get method gets the result only when the calculation is complete, otherwise it blocks until the task is completed, and then returns the result or throws an exception
- Get is evaluated only once, so the get method comes last
case
public class Demo1 {
static class MyThread1 implements Runnable {
@Override
public void run(a) {
try {
System.out.println(Thread.currentThread().getName() + "Thread enters the run method");
} catch(Exception e) { e.printStackTrace(); }}}static class MyThread2 implements Callable {
@Override
public Long call(a) throws Exception {
try {
System.out.println(Thread.currentThread().getName() + "The thread enters the call method and starts to sleep.");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "Wake up");
} catch (Exception e) {
e.printStackTrace();
}
returnSystem.currentTimeMillis(); }}public static void main(String[] args) throws ExecutionException, InterruptedException {
Runnable runnable = new MyThread1();
Callable callable = new MyThread2();
FutureTask futureTask = new FutureTask(callable);
new Thread(futureTask, "Thread two").start();
for (int i = 0; i < 10; i++) {
Long res = (Long) futureTask.get();
System.out.println(res);
}
new Thread(runnable, "Thread one").start(); }}Copy the code
7.4, summary
- When you need to perform time-consuming operations on the main thread, but don’t want to block the main thread, you can hand those jobs to the Future to be done in the background. When the main thread needs them in the Future, the Future object can be used to obtain the results of the calculation or execution status of the background job
- Generally, FutureTask is used for time-consuming calculations. The main thread can obtain results after completing its own tasks
- Retrieve the results only when the calculation is complete; Block the GET method if the calculation is not complete. Once the calculation is complete, it cannot be restarted or cancelled. The get method gets the result only when the calculation is complete, otherwise it blocks until the task is completed, and then returns the result or throws an exception.
- Only count once
8.JUC’s three helper classes
8.1. Reduce CountDownLatch
The CountDownLatch class can set a counter, then decrement by one with the countDown method, wait with await method until the counter is less than zero, and then continue with the statement following await method.
- CountDownLatch has two main methods that block when one or more threads call the await method
- Another thread calling the countDown method will decrement the counter by one (the thread calling the countDown method will not block).
- When the value of the counter becomes 0, the thread blocked by the await method is woken up and continues execution
scenario
// Scene: all six students leave the classroom, and the monitor closes the door
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "Student Number left the classroom.");
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Monitor locks the classroom door"); }}Copy the code
CyclicBarrier
The first argument to the constructor of a CyclicBarrier is the target barrier number, which is incremented each time a CyclicBarrier is executed. If the target barrier number is reached, the statement following CyclicBarrier.await() is executed. You can think of a CyclicBarrier as a plus one operation
scenario
// Scene: Collect seven dragon balls to summon the divine dragon
public class CyclicBarrierDemo {
private static final int NUMBER = 7;
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("Collect" + NUMBER + "Summon the Dragon.");
});
for (int i = 1; i <= 7; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "Dragon Balls are collected.");
try {
cyclicBarrier.await();
} catch(Exception e) { e.printStackTrace(); } }, String.valueOf(i)).start(); }}}Copy the code
8.3. Semaphore
The first parameter passed in the constructor of Emaphore is the maximum semaphore (think of as the maximum thread pool), each semaphore initialized to a maximum of one license can be distributed. Use the acquire method to obtain the license and the Release method to release the license
scenario
// Six cars vie for three parking Spaces
public class SemaphoreDemo {
public static void main(String[] args) {
// Create 3 parking Spaces
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
// Grab a parking space
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "Car Number one grabbed the parking space.");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + "Left.");
} catch (Exception e) {
e.printStackTrace();
}finally {
// The parking space is availablesemaphore.release(); } }, String.valueOf(i)).start(); }}}Copy the code
9. Read/write locks
9.1. Read/write lock
ReentrantReadWriteLock JAVA provides a read and write lock. ReentrantReadWriteLock represents two locks. One is a write-related lock, called an exclusive lock
1 Prerequisites for a thread to enter the read lock:
- There are no write locks for other threads
- There is no write request, or there is a write request, but the calling thread and the thread holding the lock are the same (reentrant lock).
Prerequisites for a thread to enter a write lock:
- There are no read locks for other threads
- There are no write locks for other threads
3 Read/write lock three important features
- Fair selection: Support unfair (default) and fair lock acquisition methods, throughput is still unfair rather than fair.
- Re-entry: Both read and write locks support thread re-entry.
- Lock degradation: A write lock can be degraded to a read lock by obtaining a write lock, acquiring a read lock, and releasing the write lock.
9.2, ReentrantReadWriteLock
ReentrantReadWriteLock implements the ReadWriteLock interface. The ReadWriteLock interface defines the specifications for obtaining read locks and write locks. The Serializable interface can be serialized. ReentrantReadWriteLock implements its own serialization logic in the source code.
9.3, case
class MyCache {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
/ / data
public void put(String key, Object value) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "Start writing.");
TimeUnit.MICROSECONDS.sleep(300);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "Finished");
} catch (Exception e) {
e.printStackTrace();
} finally{ readWriteLock.writeLock().unlock(); }}/ / read the data
public Object get(String key) {
Object res = null;
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "Start reading");
TimeUnit.MICROSECONDS.sleep(300);
res = map.get(key);
System.out.println(Thread.currentThread().getName() + "Finished reading.");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
returnres; }}public class Demo {
public static void main(String[] args) {
MyCache m = new MyCache();
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
m.put(num + "", num);
}, String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
m.get(num + ""); }, String.valueOf(i)).start(); }}}Copy the code
10.BlockingQueue blocks the queue
10.1 Overview of Blocking queues
In the Concurrent package, BlockingQueue solves the problem of efficiently and securely transferring data in multiple threads. A blocking queue, as its name implies, is first a queue, through a shared queue, data can be input from one end of the queue, output from the other end;
10.2 Architecture of blocking queues
When the queue is empty, access to and operation of elements from the queue will be blocked When the queue is full, the operation of adding elements from the queue will be blocked to access elements from the empty queue of the thread will be blocked, until the other threads to empty the queue insert a new element Trying to add new elements to the full the queue of the thread will be blocked, Until another thread removes one or more elements from the queue or empties it completely, leaving the queue idle and newly added
10.3 Blocking queue Classification
- ArrayBlockingQueue A bounded blocking queue composed of array structures
- LinkedBlockingQueue A bounded (but size defaults to integer.max_value) blocking queue consisting of a linked list structure
10.4 Blocking queue core methods
- In the data
- Offer (anObject): If possible, add anObject to BlockingQueue, return true if BlockingQueue can hold it, false otherwise.
- Offer (E O, long Timeout, TimeUnit Unit) : You can set a waiting time. If you cannot add BlockingQueue to the queue within the specified time, the BlockingQueue will fail
- Put (anObject): adds anObject to BlockingQueue. If there is no room in the BlockQueue, the thread calling this method is blocked until there is room in the BlockingQueue.
- To get the data
- Poll (time): Poll (time): Removes the first object in BlockingQueue. If it cannot be retrieved immediately, wait for the time parameter and return null if it cannot be retrieved
- Poll (long timeout, TimeUnit unit) : a team of the first object removed from a BlockingQueue, if within a specified time, queue once data, then immediately return to the data in the queue. Otherwise, no data is retrieved until time out, and failure is returned
- Take (): removes the first queued object from BlockingQueue. If BlockingQueue is empty, block the queue until new data is added to the BlockingQueue.
- DrainTo (): Gets all available data objects from BlockingQueue at once (you can also specify how many data objects to get). There is no need to batch lock or release lock multiple times.
11. ThreadPool thread pool
11.1 introduction to thread pools
advantage
The job of the thread pool is to control the number of threads running, queue tasks during processing, and then start those tasks after the thread is created. If the number of threads exceeds the maximum number, the exceeding number of threads queue up and wait for other threads to complete, and then pull the task from the queue to execute.
The characteristics of
- Reduced resource consumption: Reduces the cost of thread creation and destruction by reusing created threads.
- Improved response time: When a task arrives, it can be executed immediately without waiting for a thread to be created.
- Improve manageability of threads: Threads are scarce resources. If they are created without limit, they will not only consume system resources, but also reduce system stability. Thread pools can be used for unified allocation, tuning and monitoring.
- Thread pools in Java are implemented by the Executor framework, which uses the Executor, Executors, ExecutorService, and ThreadPoolExecutor classes
11.2. Parameter Description of thread pool
1 Common Parameters
- CorePoolSize Specifies the number of core threads in the thread pool
- MaximumPoolSize Maximum number of threads that can hold
- KeepAliveTime indicates the keepAliveTime of idle threads
- Unit Unit of survival time
- WorkQueue Stores queues of submitted but unexecuted tasks
- ThreadFactory Creates the factory class for the thread
- Handler Indicates the rejection policy for waiting for the queue to be full
When the number of submitted tasks is greater than (workqueue.size () + maximumPoolSize), the thread pool rejection policy is triggered
2 Rejection Strategy
CallerRunsPolicy: When the reject policy is triggered, the task is run directly using the calling thread as long as the thread pool is not closed. Generally, concurrency is small and does not require high performance. Failure is not allowed. However, because the caller runs the task by himself, if the task is submitted too fast, the program may be blocked, resulting in a large loss of performance and efficiency
AbortPolicy: discard task, and throw refuse to enforce RejectedExecutionException exception information. Default reject policy for the thread pool. Exceptions must be handled properly. Otherwise, the current execution process will be interrupted and subsequent tasks will be affected.
DiscardPolicy: Simply discard, nothing else
DiscardOldestPolicy: Discards the oldest task in the blocking workQueue and adds a new task to the queue if the thread pool is not closed. DiscardOldestPolicy: Removes the oldest task in the blocking workQueue and adds a new task to the queue if the thread pool is not closed
11.3 Types and creation of thread pools
1 newCachedThreadPool(common)
Function: Create a cacheable thread pool. If the length of the thread pool exceeds the processing requirement, you can recycle idle threads flexibly. If no thread pool is available, create a new thread.
Features: • The number of threads in the thread pool is not fixed and can reach the maximum value (interger.max_value) • Threads in the thread pool can be reused and reclaimed by cache (the reclaimed time is 1 minute by default) • When there are no available threads in the thread pool, a new thread is created
Create a way
public static ExecutorService newCachedThreadPool(a){
/** * corePoolSize Specifies the number of core threads in the thread pool. * maximumPoolSize Specifies the maximum number of threads that can hold. * keepAliveTime Specifies the lifetime of idle threads * threadFactory Creates a factory class that can omit * handler's rejection policy when the queue is full: can omit */
return new ThreadPoolExecutor(0,
Integer.MAX_VALUE,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<>(), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
Copy the code
scenario
This is suitable for scenarios where you create a thread pool that can be expanded indefinitely, the server is under light load, execution time is short, and there are many tasks
2 newFixedThreadPool(common)
role
Create a reusable thread pool with a fixed number of threads to run in a shared unbounded queue. At any given point, most threads will be active to process a task. If the attached task is submitted while all threads are active, the attached task will wait in the queue until there are available threads. If any thread terminates due to failure during execution prior to closure, a new thread will replace it to perform subsequent tasks (if needed). Threads in the pool will remain in existence until a thread is explicitly closed.
Characteristics of the
• Threads can be used repeatedly and remain in the queue until the display is closed • Threads that exceed a certain number of threads must wait in a queue when they are submitted
Create a way
public static ExecutorService newFixedThreadPool(a){
/** * corePoolSize Specifies the number of core threads in the thread pool. * maximumPoolSize Specifies the maximum number of threads that can hold. * keepAliveTime Specifies the lifetime of idle threads * threadFactory Creates a factory class that can omit * handler's rejection policy when the queue is full: can omit */
return new ThreadPoolExecutor(10.10.0L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
Copy the code
scenario
This is suitable for services where the number of threads can be predicted, or scenarios where the server is heavily loaded and the number of threads is strictly limited
3 newSingleThreadExecutor(Common)
role
Create an Executor that uses a single worker thread and runs it as an unbounded queue. (Note that if this single thread is terminated due to a failure during execution prior to closure, a new thread will replace it to perform subsequent tasks if needed). Each task is guaranteed to be executed sequentially and that no more than one thread is active at any given time. Unlike the equivalent newFixedThreadPool, you are guaranteed to use other threads without reconfiguring the executable returned by this method.
Characteristics of the
A maximum of 1 thread is executed in the thread pool, after which the submitted thread activity is queued for execution
Create a way
public static ExecutorService newSingleThreadExecutor(a){
/** * corePoolSize Specifies the number of core threads in the thread pool. * maximumPoolSize Specifies the maximum number of threads that can hold. * keepAliveTime Specifies the lifetime of idle threads * threadFactory Creates a factory class that can omit * handler's rejection policy when the queue is full: can omit */
return new ThreadPoolExecutor(1.1.0L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
Copy the code
4 newScheduleThreadPool
role
Create a thread pool with corePoolSize as passed in and the maximum number of threads is an integer
Characteristics of the
-
A thread pool has a specified number of threads, even empty threads are retained
-
Thread activities can be timed or deferred
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
Copy the code
scenario
Applicable to scenarios where multiple background threads are required to perform periodic tasks
5 newWorkStealingPool
Jdk1.8 provides a thread pool that uses the underlying ForkJoinPool implementation to create a thread pool with multiple task queues to reduce the number of connections and create threads with currently available CPU cores to execute tasks in parallel
Create a way
public static ExecutorService newWorkStealingPool(int parallelism) {
/** * Parallelism: Parallelism level, usually default to the number of processors available to the JVM * factory: used to create threads for use in ForkJoinPool. * Handler: used to handle exceptions that are not handled by the worker thread. Default is NULL. * asyncMode: used to control the working mode of the WorkQueue: queue -- anti-queue */
return new ForkJoinPool(parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null.true);
}
Copy the code
scenario
This method is suitable for time-consuming and parallel execution scenarios
11.4. Thread pool case demonstration
public class ThreadPoolDemo {
public static void main(String[] args) {
ThreadPoolExecutor threadService = new ThreadPoolExecutor(3.3.60l, TimeUnit.SECONDS, new LinkedBlockingDeque()
, Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
try{
for (int i = 1; i <= 10; i++) {
threadService.execute(() -> {
System.out.println(Thread.currentThread().getName() + "Start selling tickets.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "Tickets closed."); }); }}catch (Exception e) {
e.printStackTrace();
} finally{ threadService.shutdown(); }}}Copy the code
11.5. How thread pools work at the bottom
- After a thread pool is created, the number of threads in the pool is zero
- When the execute() method is called to add a request task, the thread pool makes the following judgments:
- If the number of running threads is less than corePoolSize, create a thread to run the task immediately.
- If the number of running threads is greater than or equal to corePoolSize, the task is queued;
- 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.
- If the queue is full and the number of running threads is greater than or equal to maximumPoolSize, the thread pool initiates a saturation denial policy to execute
- When a thread completes a task, it takes the next task from the queue and executes it
- When a thread has nothing to do for more than a certain amount of time, the thread decides:
- If the number of threads currently running is greater than corePoolSize, the thread is stopped.
- So after all the tasks in the thread pool are complete, it will eventually shrink to the size of corePoolSize.
11.6 Precautions
It is recommended that you manually create a thread pool using ThreadPoolExecutor and its seven parameters