java中的executor与线程池

executor框架的由来:

为每个线程分配一个线程是不太现实的:

1.线程的生命周期开销太高

2.资源耗尽

3.稳定性,不同平台客使用的线程数不同,而且受制于JVM启动参数,Tread构造中的请求栈大小,以及底层操作系统对线程的限制。

executor实现了对生命周期的支持,信息收集、应用程序管理机制和性能监视等机制。

一、Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,,最常用的三种线程池:

1.newFixedThreadPool(int nThreads)    创建固定大小的线程池,调用ThreadPoolExecutor的5个参数的构造器:

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

 

2.newSingleThreadExecutor()  创建只有一个线程的线程池

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

3.newCachedThreadPool()     创建一个不限线程数上限(实际最大为Integer.MAX,近视无上限)的线程池,任何提交的任务都将立即执行

        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());

二、. ThreadPoolExecutor的7大构造参数:

public ThreadPoolExecutor( int corePoolSize, // 线程池长期维持的线程数,即使线程处于Idle状态,也不会回收。

int maximumPoolSize, // 线程数的上限 

long keepAliveTime, TimeUnit unit, // 超过corePoolSize的线程的idle时长, // 超过这个时间,多余的线程会被回收。

BlockingQueue workQueue, // 任务的排队队列 
ThreadFactory threadFactory, // 新线程的产生方式 
RejectedExecutionHandler handler) // 拒绝回掉

这些参数中,比较容易引起问题的有corePoolSizemaximumPoolSizeworkQueue以及handler

  • corePoolSizemaximumPoolSize设置不当会影响效率,甚至耗尽线程;
  • workQueue设置不当容易导致OOM;
  • handler设置不当会导致提交任务时抛出异常。

线程池给我们提供了几种常见的拒绝策略:
java中的executor与线程池_第1张图片

拒绝策略 拒绝行为
AbortPolicy 抛出RejectedExecutionException
DiscardPolicy 什么也不做,直接忽略
DiscardOldestPolicy 丢弃执行队列中最老的任务,尝试为当前提交的任务腾出位置
CallerRunsPolicy 直接由提交任务者执行这个任务

线程池默认的拒绝行为是AbortPolicy,也就是抛出RejectedExecutionHandler异常,该异常是非受检异常,很容易忘记捕获。如果不关心任务被拒绝的事件,可以将拒绝策略设置成DiscardPolicy,这样多余的任务会悄悄的被忽略。

 

三、ExecutorService的生命周期

JVM必须等待所有线程结束后,才会正常退出,无法关闭executor,jvm将无法正确退出。

1.运行

2.关闭

3.已终止

shutdown将继续执性已经提交的任务,包括还未执行的任务。shutdownNow是一种粗暴的关闭线程池的手段,它将尝试关闭,不会再启动队列 里的任务。

ExecutorService必须显示调用关闭(shutdown或shutdownNow),不然ExecutorService一直处于运行态。

ExecutorService关闭后,再提交新的任务,将抛出RejecException的未检查异常,等待所有任务执行完毕后,ExcecutorService进入已终止状态。(可以显示调用awaitTermination等待终止,通常在此之后会立即调用shutdown,也可以使用isTerminated轮询,查询ExecutorService状态)

 

注意:一般不会直接使用executor,存在oom问题,在一些大公司会对原始的executor进行封装使用。

 

四、线程池配置管理

1.考虑CPU密集型和IO密集型

2.考虑硬件核数。

 

 

 

 

参考:https://www.cnblogs.com/CarpenterLee/p/9558026.html

你可能感兴趣的:(J.U.C)