Java中的ThreadPoolExecutors

ThreadPoolExecutors作为JDK中提供的线程池类,经常被用来处理大量异步任务。为了能够被广泛的使用,该类提供了很多参数和可扩展的钩子,用来改变线程池的行为。

ThreadExecutors提供的参数和可扩展的钩子主要有以下几种:

  • corePoolSize: 线程池的核心线程数目
  • maximumPoolSize: 线程池的最大线程数目
  • keepAliveTime:线程的最大空闲时间。当线程池中线程数量大于核心线程数,并且线程的空闲时间大于keepAliveTime的时候,线程将会被终止
  • BlockingQueue:线程池的阻塞队列,用来传递和存储提交的任务。根据使用的阻塞队列的不同,线程池对外表现的形式不同
  • ThreadFactory: 指定生成新线程的方式
  • RejectedExecutionHandler:线程池拒绝执行新任务时的handler。

线程何时被创建?

当线程池被创建的时候,里面是没有线程的。当任务被提交到线程池中时,如果当前线程数量小于核心线程数量,那么就会创建一个新线程来执行任务,即使线程池中的线程处于空闲状态;如果当前线程数量等于核心线程数量,并且没有线程是空闲的,那么新提交的线程将会被加入到阻塞队列中,而不会创建新线程。如果阻塞队列已经满了,并且当前线程数量小于指定的最大线程数,那么将会创建一个新线程来处理任务。最极端的情况下,阻塞队列已满且线程数量达到最大,那么线程池将拒绝执行任务,调用RejectedExecutionHandler来拒绝任务。

线程何时被销毁?

当线程池中线程的数量小于等于corePoolSize时,那么线程将不会被销毁;如果线程池中线程的数量大于corePoolSize,那么当线程的空闲时间大于keepAliveTime时,线程将会被销毁,直到数量等于corePoolSize。

阻塞队列对线程池的影响

  • 直接交付:同步队列(例如SynchronousQueue),提交到线程池中的任务将直接交给线程处理,队列不会持有任务。如果当前线程池中没有可用的线程来处理,该任务将会被拒绝执行。因此,当任务提交的速度大于线程的处理速度时,同步队列线程池需要将其最大线程数目调整为无限大。
  • 无界队列:如果在创建线程池的时候指定使用无界队列(例如LinkedBlockingQueue),那么当任务提交到线程池的时候,如果线程池中的核心线程正忙,任务将被塞入阻塞队列中,等待被执行。也就是说,线程池中永远也不可能存在多于核心线程数量的线程。(线程池的最大线程数目配置在这里没用)
  • 有界队列:有界队列(例如ArrayBlockingQueue)配合有限的最大线程数量一起使用能够防止资源被耗尽,但是也更加难以调控。队列的大小和最大线程数量相互影响。使用大容量的队列小的线程

拒绝任务执行

当线程池中的线程数量达到最大值,并且阻塞队列已经满了的情况下,新提交的任务将会被拒绝执行,根据创建线程池中指定的RejectedExecutionHandler的不同,线程池拒绝执行任务的表现形式也不相同,默认拒绝策略为ThreadPoolExecutor.AbortPolicy,即抛出异常

代码示例:

ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 8, 2, TimeUnit.MINUTES
        , new ArrayBlockingQueue(10), new ThreadFactory() {
    private int num = 0;

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, String.format("AsyncThreadProcessor-%d", num++));
    }
}, new ThreadPoolExecutor.AbortPolicy());

你可能感兴趣的:(java并发编程)