ThreadPoolExecutor的使用

ThreadPoolExecutor的使用,第1张

为何使用线程池

1. 复用线程,减少线程创建和销毁带来的开销

2. 主动控制线程数量,完成并发控制

3. 简化对线程的管理难度

可以不用线程池吗?

可以,对于简单的多线程任务可直接new Thread处理。如果不使用线程池,还想减少开销的话,需要自行管理线程。

四个常用构造器
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue);

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          ThreadFactory threadFactory);

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          RejectedExecutionHandler handler);

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler);

主要涉及的参数:

int corePoolSize:核心线程数。代表线程池主要用来执行任务的线程的数量。

int maximumPoolSize:最大线程数。当核心线程处理不过来的时候,会创建一些非核心线程一起处理。核心线程+非核心线程数的最大值就是最大线程数。

long keepAliveTime:非核心线程的最大空闲时间 。当任务数量逐渐稀疏以后,非核心线程逐渐得以空闲,达到最大空闲时间后,会被线程池销毁。当allowCoreThreadTimeout()设置为true时,核心线程也不例外,超过最大空闲时间也会被销毁。

TimeUnit unit:keepAliveTime的时间单位 

BlockingQueue workQueue:阻塞队列。 当前核心线程达到最大值时,优先向阻塞队列进行填充。

  1. LinkedBlockingQueue

    链式阻塞队列,底层数据结构是链表,默认大小是Integer.MAX_VALUE,也可以指定大小。

  2. ArrayBlockingQueue

    数组阻塞队列,底层数据结构是数组,需要指定队列的大小。

  3. SynchronousQueue

    同步队列,内部容量为0,每个put *** 作必须等待一个take *** 作,反之亦然。

  4. DelayQueue

    延迟队列,该队列中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素 。

ThreadFactory threadFactory:线程工厂,用于为线程池提供线程。如果不指定,会采用默认的工厂。

static class DefaultThreadFactory implements ThreadFactory {
    // 省略属性
    // 构造函数
    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
        Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
            poolNumber.getAndIncrement() +
            "-thread-";
    }

    // 省略
}

RejectedExecutionHandler handler:拒绝策略。当线程达到最大线程数时,将采用拒绝策略处理后续的任务。 

  1. ThreadPoolExecutor.AbortPolicy:默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常。

  2. ThreadPoolExecutor.DiscardPolicy:丢弃新来的任务,但是不抛出异常。

  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列头部(最旧的)的任务,然后重新尝试执行程序(如果再次失败,重复此过程)。

  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。

shutdown和shutdownNow的区别
  • 调用shutdown()方法后线程池不能接受新的任务,清除一些空闲worker,不会等待阻塞队列的任务完成。

  • 调用shutdownNow()方法后线程池不能接受新的任务,中断所有线程,阻塞队列中没有被执行的任务全部丢弃。此时,poolsize=0,阻塞队列的size也为0

线程池的升级流程
  1. 线程总数量 < corePoolSize,无论线程是否空闲,都会新建一个核心线程执行任务。注意,这一步需要获得全局锁。
  2. 线程总数量 >= corePoolSize时,新来的线程任务会进入任务队列中等待,然后空闲的核心线程会依次去缓存队列中取任务来执行。
  3. 缓存队列满了,会创建非核心线程去执行这个任务。注意,这一步需要获得全局锁。
  4. 缓存队列满了, 且总线程数达到了maximumPoolSize,则会采取拒绝策略进行处理。

 

几种常见的线程池
newCachedThreadPool:缓存队列。

特点:核心线程数为0,来一个任务就创建一个线程,容易造成线程数过大的问题。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue());
}
newFixedThreadPool:固定线程数。

特点:核心线程数等于最大线程数,没有非核心线程。通过等待队列实现处理速度的控制。容易造成OOM。

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue());
}
newScheduledThreadPool:定时处理线程池。 

特点:支持定时或周期性执行任务。也容易OOM

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

//ScheduledThreadPoolExecutor():
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}
 newSingleThreadExecutor:单线程。

特点:核心线程数等于最大线程数等于1,没有非核心线程。通过等待队列实现多余任务的处理,容易造成OOM。

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/734304.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存