线程池之ThreadPoolExecutor概述

ThreadPoolExecutor提供了四个构造方法:

 

我们以最后一个构造方法(参数最多的那个),对其参数进行解释:

public ThreadPoolExecutor( int corePoolSize,  // 1
                             int maximumPoolSize,   // 2
                             long keepAliveTime,   // 3
                             TimeUnit unit,   // 4
                             BlockingQueue<Runnable> workQueue,  // 5
                             ThreadFactory threadFactory,   // 6
                             RejectedExecutionHandler handler ) {  //7
       if (corePoolSize <  0 ||
           maximumPoolSize <=  0 ||
           maximumPoolSize < corePoolSize ||
           keepAliveTime <  0 )
           throw new IllegalArgumentException();
       if (workQueue ==  null || threadFactory ==  null || handler ==  null )
           throw new NullPointerException();
       this .corePoolSize = corePoolSize;
       this .maximumPoolSize = maximumPoolSize;
       this .workQueue = workQueue;
       this .keepAliveTime = unit.toNanos(keepAliveTime);
       this .threadFactory = threadFactory;
       this .handler = handler;
   }
序号 名称 类型 含义
1 corePoolSize int 核心线程池大小
2 maximumPoolSize int 最大线程池大小
3 keepAliveTime long 线程最大空闲时间
4 unit TimeUnit 时间单位
5 workQueue BlockingQueue<Runnable> 线程等待队列
6 threadFactory ThreadFactory 线程创建工厂
7 handler RejectedExecutionHandler 拒绝策略

自定义线程池:

public class ThreadPoolTest {
    public static void main(String[] args)  throws IOException {
        int corePoolSize =  2 ; // 核心线程大小
        int maximumPoolSize =  4 ; // 最大线程池大小
        long keepAliveTime =  10 ;  // 线程空闲10s后自动结束
        TimeUnit unit = TimeUnit.SECONDS;
        // ArrayBlockingQueue,该阻塞队列底层维护了一个定长数组(创建对象必须指定容量)
        BlockingQueue<Runnable> workQueue =  new ArrayBlockingQueue<>( 2 );
        ThreadFactory threadFactory =  new NameTreadFactory(); // 自定义线程工厂
        RejectedExecutionHandler handler =  new MyIgnorePolicy();  // 自定义拒绝策略
        // handler = new ThreadPoolExecutor.AbortPolicy();// 无法处理新任务会抛出RejectedExecutionException异常
        // 创建线程池对象
        ThreadPoolExecutor executor =  new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
                unit, workQueue, threadFactory, handler);
        executor.prestartAllCoreThreads();  // 预启动所有核心线程
        // 创建10个任务对象提交到线程池中
        for ( int i =  1 ; i <=  10 ; i++) {
            MyTask task =  new MyTask(String.valueOf(i));
            executor.execute(task);
        }
        System.in.read();  //阻塞主线程
    }

    // 任务对象
    static class MyTask  implements Runnable {
        private String name;

        public MyTask(String name) {
            this .name = name;
        }

        @Override
        public void run() {
            try {
                System.out.println( this .toString() +  " is running!" );
                Thread.sleep( 3000 );  //让任务执行慢点
            }  catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return "MyTask [name=" + name +  "]" ;
        }
    }

    // 自定义拒绝策略
    static class MyIgnorePolicy  implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            doLog(r, executor);
        }

        private void doLog(Runnable r, ThreadPoolExecutor e) {
            // 可做日志记录等
            System.err.println(r.toString() +  " rejected" );
//          System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
        }
    }

    // 线程工厂类
    static class NameTreadFactory  implements ThreadFactory {
        private final AtomicInteger mThreadNum =  new AtomicInteger( 1 );

        @Override
        public Thread newThread(Runnable r) {
            Thread t =  new Thread(r,  "my-thread-" + mThreadNum.getAndIncrement());
            System.out.println(t.getName() +  " has been created" );
            return t;
        }
    }

}

输出结果如下:

该线程池同一时间最多处理4个任务,2个任务处于等待对列中,其余的任务都会被拒绝执行。

Tips:

在默认情况下,只有当新任务到达时,才开始创建和启动核心线程,但是我们可以使用 prestartCoreThread() 和 prestartAllCoreThreads() 方法动态调整。

prestartCoreThread() :创一个空闲任务线程等待任务的到达

prestartAllCoreThreads() :创建核心线程池数量的空闲任务线程等待任务的到达


 线程池的处理流程主要分为3步:

  • 当在execute(Runnable)方法中提交的新任务后,线程池先判断线程数是否达到了核心线程数(corePoolSize)。如果未达到线程数,则创建核心线程处理任务;否则,就执行下一步;
  • 接着线程池判断任务队列是否满了。如果没满,则将任务添加到任务队列中;否则,执行下一步;
  • 接着因为任务队列满了,线程池就判断线程数是否达到了最大线程数。如果未达到,则创建非核心线程处理任务;否则,就执行饱和策略,默认会抛出RejectedExecutionException异常。
 
通过设置corePoolSize和maximumPoolSize相同,您可以创建一个固定大小的线程池。
通过将maximumPoolSize设置为基本上无界的值,例如Integer.MAX_VALUE,您可以允许池容纳任意数量的并发任务。
通常,核心和最大池大小仅在构建时设置,但也可以使用setCorePoolSizesetMaximumPoolSize进行动态更改。
饱和策略:RejectedExecutionHandler
拒绝任务有两种情况:1. 线程池已经被关闭;2. 任务队列已满且maximumPoolSizes已满;
无论哪种情况,都会调用RejectedExecutionHandler的rejectedExecution方法。预定义了四种处理策略:
  • AbortPolicy:默认策略,抛出RejectedExecutionException运行时异常;
  • CallerRunsPolicy:这提供了一个简单的反馈控制机制,可以减慢提交新任务的速度;
  • DiscardPolicy:直接丢弃新提交的任务;
  • DiscardOldestPolicy:如果执行器没有关闭,队列头的任务将会被丢弃,然后执行器重新尝试执行任务(如果失败,则重复这一过程);
    我们可以自己定义RejectedExecutionHandler,以适应特殊的容量和队列策略场景中。
posted @ 2022-03-04 14:22  danielzzz  阅读(50)  评论(0)    收藏  举报