线程池核心:三大方法、七大参数、四种拒绝策略

池化技术

所谓的池化技术,通俗来讲就是:提前准备好资源,要用就从这里拿,用完再换回来。这样做的好处:对于那写创建销毁很费时的资源,可以减少这方面时间的消耗,优化资源利用。

线程池

主要解决两个问题:

  • 当执行大量异步任务时线程池能提供较好的性能。(线程的复用)
  • 线程池提供了一种资源限制和管理的手段。(如线程的个数)

好处:

1、降低资源的消耗
2、提高相应的速度
3、方便管理
4、线程复用、可以控制最大并发数、管理线程

线程池三大方法(不推荐使用)

//三种方法
ExecutorService threadPool = Executors.newSingleThreadExecutor();//单例,只有一个线程
ExecutorService threadPool = Executors.newFixedThreadPool(5);//固定,可以创建有指定数量的线程
ExecutorService threadPool = Executors.newCachedThreadPool();//缓存,程序根据情况创建线程数量

可以看出三种方法都基于Executors。Executors其实是一个工具类,它提供了很多静态方法,可根据用户的选择返回不同的线程池实例。

在阿里巴巴开发手册中 (不允许使用Executors)

所谓的OOM指的是OutOfMemoryError,ThreadPoolExecutor会在下面介绍到。

三大方法源码分析
  • newSingleThreadExecutor()
 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  • newFixedThreadPool()
 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • newCachedThreadPool()
  public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

通过源码可以发现:三大方法本质上返回的都是一个ThreadPoolExecutor对象。
分析ThreadPoolExecutor并且找到参数最全的构造方法:发现有七个参数。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        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;
    }

七大参数

ThreadPoolExecutor各参数的涵义:

public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
                          int maximumPoolSize, //最大核心线程池大小
                          long keepAliveTime, // 存活时间
                          TimeUnit unit, // 超时单位
                          BlockingQueue<Runnable> workQueue, // 阻塞队列
                          ThreadFactory threadFactory, //线程工厂
                          RejectedExecutionHandler handler //拒绝策略) 
  • corePoolSize:核心线程池大小。线程池的基本大小,在没有任务执行时的大小,并且只有当线程工作队列满了后才会创建超出这个数量的线程。
  • maximumPoolSize:最大线程池大小。创建线程的数量不会超过maximumPoolSize的值。
  • keepAliveTime:存活时间。超过了这个时间如果还没有被调用就会释放。
  • unit:超时单位。设置keepAliveTime的单位。
  • workQueue:阻塞队列。用于保存执行的任务的阻塞队列。(如基于数组的有界ArrayBlockingQueue、基于链表的无界LinkedBlocking、同步队列SynchronousQueue、优先级队列PriorityBlockingQueue)
  • threadFactory:线程工厂。用于创建线程,一般大多数情况下默认情况 Executors.defaultThreadFactory()。
  • handler:线程池拒绝策略。当队列满并且线程个数达maximumPoolSize后会采取的策略。有四种拒绝策略AbortPolicy() 、 CallerRunsPolicy() 、 DiscardPolicy() 、 DiscardOldestPolicy()

读者可以根据七大参数去分析上面三大方法中的参数。

四种拒绝策略

在七大参数中提到:当队列满并且线程个数达maximumPoolSize后会采取拒绝策略。
ThreadPoolExecutor中有四个静态内部类实现了RejectedExecutionHandler,对应的就是四种拒绝策略。

四种拒绝策略:

  • AbortPolicy():抛出异常。当队列和最大线程数量都满了时,如果还有线程进来则不处理该线程并且抛出异常。
  • CallerRunsPolicy():使用调用者所在线程来运行任务。“打发”给调用者所在线程。
  • DiscardPolicy():默默丢弃,不抛出异常。
  • DiscardOldestPolicy():调用poll丢弃一个任务,执行当前线程。(被拒绝后,将最早就入队列的任务删掉,再尝试加入队列)

ThreadPoolExecutor使用

 @Test
    public void test() {
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1,5,60, TimeUnit.SECONDS,
                                                                 new ArrayBlockingQueue<Runnable>(3),new ThreadPoolExecutor.AbortPolicy());
        try {
            for (int i = 0; i < 5; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName());
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
posted @ 2021-11-16 13:33  “Kiddy”  阅读(374)  评论(0)    收藏  举报