Detailed explanation of the underlying principle of Java concurrent thread pool and source code analysis

1. Thread pool and thread performance comparison

In the case of single thread, the speed of processing tasks is greatly improved compared with the performance of using thread pool. Thread pool can be reused inside. After the thread processes the task, it can return to the thread pool to process other tasks, which greatly reduces thread destruction. and creation time.

Several thread pools that come with java:

ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService1 = Executors.newFixedThreadPool(100);
ExecutorService executorService2 = Executors.newSingleThreadExecutor();
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);

The construction parameters of the thread pool above are all created with ThreadPoolExecutor, but the parameters used are different.

The construction method used by newCachedThreadPool: corresponding parameters (number of core threads, maximum number of threads, thread survival time, thread survival time unit, queue), newCachedThreadPool has only 0 core threads, and the number of temporary threads can be infinite, so its execution efficiency is very high , SynchronousQueue is a typical producer consumer model, which is equivalent to an outsourcing company.

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                              60L, TimeUnit.SECONDS,
                              new SynchronousQueue<Runnable>())
The construction method used by newCachedThreadPool: the number of core threads and the number of temporary threads are both customized. The LinkedBlockingQueue queue is an unbounded blocking queue, which is equivalent to waiting for task processing indefinitely, but the efficiency is very low. Equivalent to a state-owned enterprise. 
new ThreadPoolExecutor(nThreads, nThreads, 
                              0L, TimeUnit. MILLISECONDS, 
                              new LinkedBlockingQueue<Runnable>())
The construction method used by newSingleThreadExecutor: the number of core threads and the number of temporary threads are both 1, which is equivalent to one person handling countless tasks. The efficiency is very fast when the task can be processed quickly, but it will be slow when the task needs to be processed. It seems very inefficient. It is equivalent to a private enterprise, and everything is done by one person. 
new FinalizableDelegatedExecutorService 
    (new ThreadPoolExecutor(1, 1, 
                            0L, TimeUnit. MILLISECONDS, 
                            new LinkedBlockingQueue<Runnable>()))

The thread pool most likely to have OOM: newCachedThreadPool, which is not an unbounded queue, will report OOM when it reaches the maximum value of memory

The previous three cases are not recommended by Ali’s specifications, but the above three can be used in businesses that cannot reach the top value of memory. Ali recommends custom thread pool ThreadPoolExecutor

 1.1 Comparison of thread pools in practice

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadDemo {

    public static void main(String[] args) {

        //定义3个线程池
        ExecutorService executorService = Executors.newCachedThreadPool();//很快
        ExecutorService executorService1 = Executors.newFixedThreadPool(100);//不快不慢
        ExecutorService executorService2 = Executors.newSingleThreadExecutor();//最慢

        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            executorService2.submit(new Task());
        }
        executorService.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }
}

1.2 ThreadPool Executor combat

/**
 * 第31个任务会拒绝任务
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //定义ThreadPoolExecutor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10));
        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            threadPoolExecutor.submit(new Task());
        }
        threadPoolExecutor.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

1.3  Interview question 1: Custom thread pool parameters

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
   
   

corePoolSize: number of core threads

int maximumPoolSize: the maximum number of threads

long keepAliveTime: Temporary thread survival time

TimeUnit unit: Temporary thread survival unit

BlockingQueue<Runnable> workQueue: task queue

ThreadFactory threadFactory: general custom factory class

RejectedExecutionHandler handler: rejection strategy, there are 4 definitions, generally we can customize the rejection strategy

AbortPolicy: RejectedExecutionException is thrown by default to reject the task 
DiscardPolicy: Abandon the task 
DiscardOldestPolicy: Throw the oldest task through the queue structure 
CallerRunsPolicy: The thread that calls the execute method executes the task

1.4  Interview Question Thread Pool Source Code Analysis Execution Schematic (TODO) 

1.5 The difference between submit() and execute methods in interview questions (TODO)

The difference between submit and execute: There is a concept of submission priority and execution priority in the thread, and the submission priority is higher than the execution priority. 
1. The execute method is in the submit method. 
2. The submit method will return a Future generic function, but execute will not return

 

 

1.6 The difference between offer() and add() in interview questions

Both add and offer are methods for adding tasks to the task queue. The difference is that the add method does not throw an exception, while the offer will throw an interrupt exception. This is the only difference between them.

 

 

1.7 newScheduledThreadPool(TODO)

1.7.1 newScheduledThreadPool combat (TODO)

1.7.2 Source code analysis (TODO)

1.8 Custom Deny Policy

There are two ways to customize the rejection policy:

//Custom rejection strategy 
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() { 
    @Override 
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 
        System.out.println("Custom rejection strategy, can be stored in database"); } 
    } 
;

The second method: implement the RejectedExecutionHandler interface and rewrite the rejectedExecution method.

import java.util.concurrent.*;

/**
 * 第31个任务会拒绝任务
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //自定义拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println("自定义拒绝策略,可以存入数据库");
            }
        };

        //定义ThreadPoolExecutor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),rejectedExecutionHandler);
        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            threadPoolExecutor.submit(new Task());
        }
        threadPoolExecutor.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Guess you like

Origin blog.csdn.net/qq_21575929/article/details/124939077