线程池(ThreadPoolExecutor)重要参数解析

ThreadPoolExecutor线程池继承ExecutorService,用来解决2个问题:

  • 执行大量异步任务的时候,通过每个线程一个任务的方法,减少线程调用开销,提升性能;
  • 设置线程池最大线程数,管理线程资源的调用。执行大量任务的时候会不断消耗线程;

常见的三种线程池:

  • newCachedThreadPool
    • 优点:任何需要的时候都会创建新线程执行任务,当有可用的空闲线程(空闲线程在60秒内如果没有使用,会将该线程终止)时会优先使用可用线程,除非无可用线程;可以运用于执行大量运行时间短的任务;
    • 缺点:不适合运行时间长的任务,因为会占着CPU资源,导致CPU性能降低;有可能会在短时间内创建大量线程执行任务;
  • newFixedThreadPool
    • 优点:corePoolSize和maximumPoolSize相同,只会产生一定数量的线程,如果线程都在使用,会优先将任务放在队列中等待,并不会再产生新的线程。适合执行运行时间较长的任务;
    • 缺点:如果线程池使用率不高,会导致大量空闲的线程,占用CPU资源。产生大量的空闲线程的原因,是因为此种线程池的keepAliveTime设置为0,也就是空闲线程永远不会被终止。反之,如果大量长时间运行任务占用了所有线程,那么其他任务要加入线程池,只能在无边界队列中等待,又会导致占着大量内存。
    • 特点:不允许线程池动态扩展核心线程数(因为maximumPoolSize被设置为等于corePoolSize),任意线程在线程池关闭前发生了异常导致该线程异常终止,会创建新的线程替代该线程。
  • newSingleThreadExecutor
    •           优点:corePoolSize和maximumPoolSize相同,并且只会产生一个线程执行任务。
    •           缺点:如果当前线程被一个长时间运行任务占用,那么新的任务只能加入无界队列中等待,导致占用大量内存,而且影响其他任务的执行效率。
    •           特点:只有一个线程执行任务,如果在线程池关闭前发生了异常导致线程异常终止,会创建新的线程替代失败的线程;任务按顺序执行;

重要参数:

corePoolSize:核心线程数,核心线程不会被终止。除非allowCoreThreadTimeOut设置为true;

maximumPoolSize:最大核心线程数,超过keepAliveTime时间的线程,将被终止;

keepAliveTime:线程允许空闲最大时间,不能小于0。如果设置该参数,线程空闲时间超过keepAliveTime后,将被终止,终止的线程范围为:corePoolSize<可能终止线程<= maximumPoolSize;

allowCoreThreadTimeOut:允许空闲核心线程超时终止,如果设置为true,则核心线程空闲时间超过keepAliveTime后,仍将被终止。

workQueue:任务等待队列,放入队列需遵循以下3个原则:

  1. 当线程池中的工作线程少于corePoolSize时,线程池优先为新任务创建线程;
  2. 当线程池中需要的线程大于corePoolSize时,线程池优先将新任务放入队列中等待;
  3. 当队列已经放满,线程池将会创建新的线程执行任务,直到线程数量等于maximumPoolSize。如果需要的线程大于maximumPoolSize,线程池将会拒绝接收。

handler:拒绝策略,以下2种情况会执行拒绝策略:

  1. 当线程池已经关闭,提交新任务时会拒绝;
  2. 当线程池设置了明确的maximumPoolSize和workQueue的最大值,并且线程池已经饱和,提交新任务会拒绝;

4种已知拒绝策略:

1,ThreadPoolExecutor.AbortPolicy,默认拒绝策略,拒绝策略会抛出RejectedExecutionException异常;

扫描二维码关注公众号,回复: 2714845 查看本文章

2,ThreadPoolExecutor.CallerRunsPolicy,使用此种策略,在执行execute方法时,会使用当前线程立即执行新任务,调用Runnable的run方法而不经过线程池执行;

3,ThreadPoolExecutor.DisgardPolicy,使用此种策略,会忽视新任务,产生的效果就是,新提交任务将被丢弃;

4,ThreadPoolExecutor.DisgardOldestPolicy,使用此种策略,会首先将workQueue中的Head元素丢弃,并且尝试执行新任务,一直循环直到该任务被线程池接收。如果该线程池关闭,新任务将被丢弃;

开发人员可以定制自己的拒绝策略,但是在处理时需要特别小心。

线程池所有状态解释:

 

重要方法:

execute():提交并执行任务,执行逻辑:

                      1,当线程池中线程数少于corePoolSize,创建新线程执行任务;

                      2,当大于corePoolSize,放入等待队列中;

                      3,当队列中已经放满,创建新线程执行任务,直到线程池线程数=maximumPoolSize。否则拒绝接收任务,并执行拒绝策略;

           shutdown():关闭线程池,只执行等待队列中的任务(但是不会等待所有任务执行完毕),不接收新任务并且终止空闲线程。 如果已经关闭但是再次执行shutdown,没有任何作用。注意:shutdown()只会执行等待队列中的任务,但是不会等待所有任务执行完毕才关闭,意味着,此时仍然有线程在运行任务,如果要等待所有运行任务关闭,可以调用awaitTermination()方法;

           shutdownNow():关闭线程池,不接收新任务,不执行等待队列中的任务,所有任务将被丢弃,并打断所有在运行中的任务,而且会返回所有未执行的任务(估计是让使用方自己决定是否后续用来执行未完成的任务)。注意:shutdownNow()不会等待所有任务执行完毕才关闭,意味着,此时仍然有线程在运行任务,如果要等待所有运行任务关闭,可以调用awaitTermination()方法;

           awaitTermination(long timeout, TimeUnit unit):先加锁,判断线程池是否关闭,如果已关闭,返回true;反之,会将当前线程置于等待状态(等待时间为方法入参,调用方控制)并将当前锁释放。如果等待超时,当前线程将重新激活,并继续判断线程池是否关闭,关闭返回true,  否则判断剩余等待时间是否小于0,小于0返回false。

          想来想去,awaiTermination可以这么用,先调用shutdownNow(),此时也许线程池还有任务在运行。那再调用awaitTermination(),确保线程池所有的任务都已终止,一次不够那么就再调用一次。

            如有不正确的地方,请指正,共同进步,某将感激不尽!

 

 

 

猜你喜欢

转载自blog.csdn.net/u013262534/article/details/81532071