java多线程中,线程池的最上层接口是Executor,ExecutorService实现了Executor,是真正的管理线程池的接口,ThreadPoolExecutor间接继承了ExecutorService,提供了多种具体的线程池实现,在日常开发中一般直接使用Executors工具类提供的几种常用ThreadPoolExecutor,下面详细介绍下ThreadPoolExecutor.

ThreadPoolExecutor基本参数

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1000L, 
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(20),
new ThreadPoolExecutor.CallerRunsPolicy());

ThreadPool模型初始化

  ThreadPool线程池初始化时,不会创建corePoolSIze的线程,也就是说在没有task进来的时候,线程池是空的,当有task进来的时候,开始创建线程,并且线程执行完task后不会销毁,而是驻留内存,直至达到corePoolSize,那什么时候线程数会再度增加达到maxPoolSize呢,这就取决于存放task的queue的size了,如果task的数量一直不超过指定的size那么就不会创建新的线程出来,反之,则会创建新的线程去执行task,那么新建出来的线程执行完task也会一直驻留内存吗?答案是不会,这时候就要看设置的keepAliveTime,如果在超过了这个时间后还是没有task去使用这个线程,则线程销毁,直至线程数等于corePoolSize.那么如果queue也满了,线程数也达到maxPoolsize,这时候怎么办呢,这时rejectHandler就会发挥作用,会根据我们指定的拒绝策略去处理这种场景.

Executors的几个默认实现

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

  1.newSingleThreadExecutor:创建一个单线程的线程池.如果这个线程在执行霍城中因为异常结束,则会创建一个新的线程来代替它,这个线程池保证所有任务的执行顺序是按照任务提交顺序进行.

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

  2.newFixedThreadPool:创建一个固定大小的线程池.看源码可知,该实现创建了一个corePoolSize等于maximumPoolSize的线程池.

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

  3.newCachedThreadPool:创建一个可缓存的线程池.看源码可知corePoolSize=0,即当线程空闲时会被回收,当线程忙碌时又可以"源源不断"的创建新线程来执行task.

  默认线程池实现中还有ScheduledThreadPoolExecutor,可以实现定时的一些功能,可用来代替Timer或者TimeTask.这里不再展开说.

线程池的堵塞队列

  如何选择线程池的堵塞队列,取决我们的业务场景,即我们希望以一种什么样的排队策略来处理任务.排队通常有3种策略,对应下面几种queue.

线程池拒绝策略

01-28 19:02