• 并发编程学习笔记(三十二、线程池源码二,ThreadPoolExecutor构造函数)


    目录:

    • corePoolSize:核心线程数量
    • workQueue:阻塞队列
    • maximumPoolSize:最大线程数量
    • threadFactory:线程工厂
    • handler:拒绝、饱和策略
    • 线程池执行原理图
    1 public ThreadPoolExecutor(int corePoolSize,
    2                           int maximumPoolSize,
    3                           long keepAliveTime,
    4                           TimeUnit unit,
    5                           BlockingQueue<Runnable> workQueue,
    6                           ThreadFactory threadFactory,
    7                           RejectedExecutionHandler handler) {
    8 }

    可参考之前的一篇文章:https://www.cnblogs.com/bzfsdr/p/13089015.html

    corePoolSize:核心线程数量

    corePoolSize:核心线程数量。

    • 核心线程将一直保存在线程池中,哪怕是处于空闲状态也可以不回收,当然你也可以通过allowCoreThreadTimeOut参数控制是否回收核心线程
    • 刚创建线程池的时候,核心线程并不会立即启动,而是等到有任务提交时才会启动preStartCoreThreadpreStartAllCoreThreads方法可以预启动核心线程,以提升效率)。

    workQueue:阻塞队列

    • BlockingQueue接口所有的实现类都可以作为阻塞队列(如之前学的ArrayBlockingQueue、LinkedBlockingQueue)。
    • 设置阻塞队列容量时需要注意一点:最好不要设置无界的阻塞队列,因为这样的话即使核心线程是处于工作状态时也会无限制的接收其它任务,导致队列过程,影响JVM性能,严重情况下可能会造成OOM(这也是Alibaba不推荐使用Executors类来直接创建线程池的原因)。

    maximumPoolSize:最大线程数量

    • 阻塞队列已满还有新的任务进来时,就会去创建非核心线程来执行任务,当然这也是有限制的,也就是不能超过maximumPoolSize
    • 非核心线程会被回收,通过keepAliveTimeunit控制空闲回收条件

    threadFactory:线程工厂

    用于定线程初始化的创建工程,默认实现为DefaultThreadFactory。

     1 static class DefaultThreadFactory implements ThreadFactory {
     2     private static final AtomicInteger poolNumber = new AtomicInteger(1);
     3     private final ThreadGroup group;
     4     private final AtomicInteger threadNumber = new AtomicInteger(1);
     5     private final String namePrefix;
     6 
     7     DefaultThreadFactory() {
     8         SecurityManager s = System.getSecurityManager();
     9         group = (s != null) ? s.getThreadGroup() :
    10                               Thread.currentThread().getThreadGroup();
    11         namePrefix = "pool-" +
    12                       poolNumber.getAndIncrement() +
    13                      "-thread-";
    14     }
    15 
    16     public Thread newThread(Runnable r) {
    17         Thread t = new Thread(group, r,
    18                               namePrefix + threadNumber.getAndIncrement(),
    19                               0);
    20         if (t.isDaemon())
    21             t.setDaemon(false);
    22         if (t.getPriority() != Thread.NORM_PRIORITY)
    23             t.setPriority(Thread.NORM_PRIORITY);
    24         return t;
    25     }
    26 }

    其实现也很简单,定义了线程组和守护线程、优先级等东西。

    当然你也可以通过实现ThreadFactory接口自定义线程工厂:

     1 /**
     2  * 线程工厂
     3  */
     4 static class NameTreadFactory implements ThreadFactory {
     5     /** 线程id **/
     6     private final AtomicInteger threadId = new AtomicInteger(1);
     7 
     8     @Override
     9     public Thread newThread(Runnable runnable) {
    10         Thread t = new Thread(runnable, "线程-" + threadId.getAndIncrement());
    11         System.out.println(t.getName() + " 已经被创建");
    12         return t;
    13     }
    14 }

    handler:拒绝、饱和策略

    当线程池数量达到最大,并且阻塞队列的容量也达到最大的时候,线程池将达到最大负载;此时再往线程池添加任务时,线程池将无法继续处理。二拒绝策略就是为了保护线程池的负载。

    ThreadPoolExecutor默认提供了4中策略,如果你还觉得不过瘾就可以实现RejectedExecutionHandler接口构建自己的策略。

    1、直接运行(若线程池还未关闭,直接运行被拒任务):CallerRunsPolicy。

    1 public static class CallerRunsPolicy implements RejectedExecutionHandler {
    2     public CallerRunsPolicy() { }
    3     
    4     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    5         if (!e.isShutdown()) {
    6             r.run();
    7         }
    8     }
    9 }

    2、不接受处理(抛出RejectedExecutionException异常):AbortPolicy。

    1 public static class AbortPolicy implements RejectedExecutionHandler {
    2     public AbortPolicy() { }
    3 
    4     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    5         throw new RejectedExecutionException("Task " + r.toString() +
    6                                              " rejected from " +
    7                                              e.toString());
    8     }
    9 }

    3、啥都不做:DiscardPolicy。

    1 public static class DiscardPolicy implements RejectedExecutionHandler {
    2     public DiscardPolicy() { }
    3 
    4     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    5     }
    6 }

    4、取舍:(舍弃最早进入队列的任务,然后执行新的任务):DiscardOldestPolicy。

     1 public static class DiscardOldestPolicy implements RejectedExecutionHandler {
     2     public DiscardOldestPolicy() { }
     3 
     4     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
     5         if (!e.isShutdown()) {
     6             e.getQueue().poll();
     7             e.execute(r);
     8         }
     9     }
    10 }

    5、自定义

     1 /**
     2  * 线程池拒绝策略
     3  */
     4 public static class MyIgnorePolicy implements RejectedExecutionHandler {
     5 
     6     @Override
     7     public void rejectedExecution(Runnable runnable, ThreadPoolExecutor e) {
     8         doLog(runnable, e);
     9     }
    10 
    11     private void doLog(Runnable runnable, ThreadPoolExecutor e) {
    12         // 可做日志记录等等
    13         System.err.println(runnable.toString() + " rejected");
    14     }
    15 }

    线程池执行原理图

  • 相关阅读:
    分享15个专业且免费的HTML5模板
    项目环境的搭建
    DNS预解析 dns-prefetch
    页面布局
    计划与准备
    Hogan的安装和使用
    代理工具--fiddle
    vue.js加入购物车小球动画
    vue.js笔记1.0
    url,href,src区别
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/13346219.html
Copyright © 2020-2023  润新知