JAVA multi-threaded thread pool, let's take a look at it! !

About thread pools in high concurrency and multithreading

definition

Thread is a scarce resource, its creation and destruction is a relatively heavy and resource-consuming operation, while Java thread depends on kernel thread, creating a thread requires operating system state switching, in order to avoid excessive resource consumption, it is necessary to reuse threads to perform multiple tasks . The thread pool is a thread cache, which is responsible for uniform allocation, tuning and monitoring of threads.

When to use thread pools:

  • The processing time of a single task is relatively short
  • The number of tasks to be processed is relatively large

Advantages of thread pools:

  • Reuse existing threads, reduce the overhead of thread creation and death, and improve performance
  • Improve responsiveness. When a task arrives, the task can execute immediately without waiting until the thread is created.
  • Improve the manageability of threads, which can be allocated, tuned and monitored uniformly.

How to create a thread pool

The Executors under the JavaJUC package provide four ways to create a thread pool and the underlying parameters (the bottom layer of the four thread creation methods uses the ThreadPoolExecutor class, which is defined according to the different parameters, and the description of the relevant parameters will be given below)

newCachedThreadPool

Definition and role

Create a thread pool that can create new threads as needed. If there are available threads in the thread pool (available means that threads exist and are idle), if not, create a new thread to execute, usually used for asynchronous tasks with relatively short execution time

    public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//此核心线程数corePoolSize为0,maximumPoolSize接近无限大
                                      60L, TimeUnit.SECONDS,//keepAliveTime存活时间为 60s,时间到自动回收
                                      new SynchronousQueue<Runnable>());//使用的是同步阻塞队列
    }

Usage example

//定义一个线程类
class RunnableThread implements Runnable{
    
    
    private int i=0;
    public RunnableThread(int i) {
    
    
        this.i = i;
    }
     public void run() {
    
    
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"执行了第"+i+"个任务!");
        }
    }
//创建10个任务
   ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
    
    
            executorService.execute(new RunnableThread(i));

        }

You can see that 10 tasks are executed after one second

newScheduledThreadPool

Definition and role

Create a thread pool that supports periodic execution and can do timed tasks, mainly used for periodic task execution scenarios

  public ScheduledThreadPoolExecutor(int corePoolSize) {
    
    
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,//maximumPoolSize接近无限大,keepAliveTime存活时间为 0纳秒,线程不会被回收
              new DelayedWorkQueue());//采用延迟队列,提交的任务按照执行时间排序到队列中
    }

Usage example

  //schedule 是ScheduledExecutorService特有的方法
ScheduledExecutorService  executorService = Executors.newScheduledThreadPool(6);
            executorService.schedule(new RunnableThread(1),6L,TimeUnit.SECONDS);
            executorService.schedule(new RunnableThread(2),5L,TimeUnit.SECONDS);
            executorService.schedule(new RunnableThread(3),4L,TimeUnit.SECONDS);
            executorService.schedule(new RunnableThread(4),3L,TimeUnit.SECONDS);
            executorService.schedule(new RunnableThread(5),2L,TimeUnit.SECONDS);

insert image description here
It can be seen that the task is executed according to the preset delay. Those who need to do timed tasks can use this thread to achieve

newFixedThreadPool

Definition and role

Create a thread pool with a fixed number of threads as needed. When there are many tasks, queue up and wait. It is suitable for scenarios where the number of tasks is fixed and stable, that is, when the concurrency pressure is determined, create the specified number of threads.

    public static ExecutorService newFixedThreadPool(int nThreads) {
    
    
        return new ThreadPoolExecutor(nThreads, nThreads,//核心线程数等于最大线程数
                                      0L, TimeUnit.MILLISECONDS,//纳秒
                                      new LinkedBlockingQueue<Runnable>()); //阻塞队列,任务量来的时候无可用线程时,入队等待
    }

Usage example

   ExecutorService  executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 6; i++) {
    
    
            executorService.execute(new RunnableThread(i));
        }

It can be seen that the three threads are executed once in the first second, and the three threads are executed repeatedly in the second second, and no new threads are created.

newSingleThreadExector

Definition and role

Create a thread pool with only a single thread, use a single worker thread to execute tasks, and ensure the orderly execution of tasks. It is suitable for the case where tasks are required to be executed in an orderly manner. It is the same as the definition of newFixedThreadPool, except that the number of threads is only one

 public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    
    
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

Usage example


   ExecutorService  executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
    
    
            executorService.execute(new RunnableThread(i));
        }

You can see that the task is executed one per second, and it is carried out in an orderly manner

The above is the creation of the four thread pools provided by Executors. It is clear from the above that the bottom layer is determined by using ThreadPoolExecutor according to different parameters. The following is mainly based on this class to analyze the underlying principle of the thread pool.

ThreadPoolExecutor

//构造方法
public ThreadPoolExecutor(int corePoolSize,  //核心线程数
                              int maximumPoolSize,  //最大线程数
                              long keepAliveTime,  //存活时间
                              TimeUnit unit,  //时间单位
                              BlockingQueue<Runnable> workQueue,  //使用队列类型,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出
                              ThreadFactory threadFactory,  //就是创建线程的线程工,可以通过自己自定义的方式去创建一个线程
                              RejectedExecutionHandler handler)//是一种拒绝策略,我们可以在任务满了后,根据采用的策略拒绝执行某些任务,java提供了四种执行策略:
   			    // AbortPolicy:中断抛出异常
    			//DiscardPolicy:默默丢弃任务,不进行任何通知
    			//DiscardOldestPolicy:丢弃掉在队列中存在时间最久的任务
    			//CallerRunsPolicy:让提交任务的线程去执行任务(对比前三种比较友好一丢丢)

The execution principle of the thread (it will be clearer if you look at the source code)

insert image description here
In actual project development, it is also recommended to use the method of manually creating a thread pool instead of the default method. This is described in the "Alibaba Development Specification" as follows:

img
Create a custom thread pool to create a thread pool based on concurrency and specific task requirements

 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 0L, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(10));
        for (int i = 0; i < 100; i++) {
    
    
            threadPoolExecutor.execute(new RunnableThread(i)
            );
        }

execute source code:The description of the source code will be supplemented later.

   int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
    
     //如果小于核心线程数的数往下执行
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
    
     //
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command); //采用拒绝策略

    private boolean addWorker(Runnable firstTask, boolean core) {
    
    
        retry:
        for (;;) {
    
    
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
    
    
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
    
    
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
    
    
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
    
    
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
    
    
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
    
    
                    mainLock.unlock();
                }
                if (workerAdded) {
    
    
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
    
    
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

The basic use and principles of thread pools are here first. You are welcome to point out the shortcomings and learn together! !

Guess you like

Origin blog.csdn.net/qq_38338409/article/details/120943640