聊聊线程池

一个通用的线程池需要提供以下4种能力,使用方根据业务场景选择适合的策略:

1.可自定义的线程数

2.回收线程的策略

3.任务队列堆积的策略

4.处理不过来时的拒绝策略

 

 

Executors里面封装了这几种比较常用的线程池,newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool、newFixedThreadPool延迟版、newSingleThreadExecutor延迟版

1.ThreadPoolExecutor的关键参数

 newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool都是对ThreadPoolExecutor的封装,延迟版的线程池是对ScheduledThreadPoolExecutor的封装,那了解ThreadPoolExecutor和ScheduledThreadPoolExecutor的参数也就能明白这几种线程池的工作原理了。

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;
    }
corePoolSize 
 可存活的线程数,这部分线程即使空闲也不会被回收,除非设置allowCoreThreadTimeOut为true
maximumPoolSize 
 最大存活的线程数
workQueue 
 堆积任务的队列
keepAliveTime 
 超过corePoolSize那部分的线程,在等待指定时间后仍没有可执行的任务,则回收线程
threadFactory 
 线程池工厂,可以设置线程名称等操作
handler 
 当可用线程为0并且队列满了的时候,会调用handler的rejectedExecution方法

 


 

 2.自带的几种拒绝执行策略

AbortPolicy 抛出异常
CallerRunsPolicy 使用调用者的线程执行该任务,即submit方法变成了同步操作
DiscardPolicy 丢弃该任务
DiscardOldestPolicy 丢弃最老的任务,重新提交该任务

 


 3.Executors线程池的配置和特点

  3.1 固定线程数,无边界队列,适合IO密集的运算

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

   活跃线程数最多为nThreads个,

  线程调用队列的take方法阻塞获取任务,不回收线程

  LinkedBlockingQueue队列大小为Integer的最大值,堆积的任务超过这个值并且可用线程数为0,就抛出RejectedExecutionException

  

  3.2 一个线程,无边界队列,适合cpu密集的运算

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

   与newFixedThreadPool类似,活跃线程为1,并且用FinalizableDelegatedExecutorService做代理,使得不能通过setMaximumPoolSize等方法修改线程池,同时重写了finalize方法,使得在线程池被GC回收的时候关闭线程池。

 

  3.3 处理不过来就创建线程,无消息堆积的能力

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

  活跃线程最大值为Integer最大值

  线程调用队列的poll阻塞60秒获取任务,超时则回收线程

  SynchronousQueue队列大小为1,无任务堆积的能力,即可用线程数为0时则抛出RejectedExecutionException

 


 

4.扩展点

 

protected void terminated() { }
protected void afterExecute(Runnable r, Throwable t) { }
protected void terminated() { }

 


 

5.ScheduledThreadPoolExecutor的关键参数

public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory,
                                       RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
              new DelayedWorkQueue(), threadFactory, handler);
    }
corePoolSize
 可存活的线程数,这部分线程即使空闲也不会被回收,如果设置allowCoreThreadTimeOut为true会抛异常
threadFactory
线程池工厂,可以设置线程名称等操作
handler
当可用线程为0并且队列满了的时候,会调用handler的rejectedExecution方法

  虽然ScheduledThreadPoolExecutor是继承了ThreadPoolExecutor,但是线程池的线程数最大为corePoolSize,设置maximumPoolSize是无效的。

 


 

 

6.延迟和定期执行的方法

 

public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);

  延迟指定时间执行该任务,只执行一次

 

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);

  延迟指定时间执行该任务,并按提交任务的时候算起,固定的时间间隔定期执行。如果线程数不够的时候,则排队等待,不会被多个线程并发执行。

 

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

  延迟指定时间执行该任务,并按上一次完成任务的时候算起,固定的时间间隔定期执行。如果线程数不够的时候,则排队等待,不会被多个线程并发执行。

posted @ 2017-07-23 01:04  技塑人生  阅读(929)  评论(0编辑  收藏  举报