JUC之线程池的实现原理以及拒绝策略

线程池实现原理

向线程池提交任务后,线程池如何来处理这个任务,之前我们了解了7个参数,我们通过这些参数来串联其线程池的实现原理。

image-20220119163714794

image-20220119163758655

1、在创建了线程池后,开始等待请求

2、当调用execute()方法添加请求任务时:

  • 如果正在运行的线程小于corePoolSize(核心线程数),那么马上创建线程执行任务;
  • 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入阻塞队列中;
  • 如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize(最大线程数),那么再创建非核心线程来执行任务
  • 如果这个时候队列满了且正在运行的线程数量还大于或等于maximumPoolSize(最大线程数),那么线程池会启动饱和拒绝策略来执行

3、当一个线程完成任务时,他会从队列中取出下一个任务来执行

4、当一个线程无事可做并超过了一定的时间(KeepAliveTime)时,线程会回收。

拒绝策略

等待队列已经排满,再也塞不下新任务,同时线程池中的max线程也到达上限了,无法继续执行新任务服务,这时候就需要据拒绝策略。

内置的拒绝策略有四种:

  1. AbortPolicy(默认的拒绝策略):直接抛出RejectedExecutionException异常
  2. CallerRunPolicy:回退任务,该策略不抛弃任务,也不抛出异常,而是将任务会退给调用者,从而降低新任务的流量
  3. DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务。
  4. DiscardPolicy:该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略。

根据阿里巴巴手册,定义线程池需要使用ThreadPoolExecutor来创建:

package com.JucPool;

import java.util.concurrent.*;

public class demo1 {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2,
            	//根据自己的处理器数量+1
                Runtime.getRuntime().availableProcessors()+1,
                2L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        try{
            for (int i = 0; i < 8; i++) {
                executor.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"\t任务执行");
                });
            }
        } finally {
            executor.shutdown();
        }
    }
}

如果项目时CPU密集型,则设置的线程池的最大线程数是:CPU数+1~2个。

posted @ 2022-01-19 16:40  Xbhog  阅读(339)  评论(0编辑  收藏  举报