线程池

作者: hcq0514 | 来源:发表于2019-09-26 19:43 被阅读0次

    Executors类创建

            ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
            ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    

    这种方式是jdk自带的创建线程池的方式,阿里的规范里是不推荐这样创建的

    线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
    1)newFixedThreadPool和newSingleThreadExecutor:
      主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
    2)newCachedThreadPool和newScheduledThreadPool:
      主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

    • Executors类创建源码(底层都是调用new ThreadPoolExecutor)


      image.png

    ThreadPoolExecutor创建

    • 构建函数(7参数)
      public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
        }
    
    name 含义
    corePoolSize 核心线程数
    maximumPoolSize 最大线程数
    keepAliveTime 线程池中超过 corePoolSize 数目的空闲线程最大存活时间
    unit 存活时间单位
    workQueue 阻塞任务队列
    threadFactory 新建线程工厂
    handler 拒绝策略,当请求的线程数超过maximumPoolSize+workQueue时,交过handler处理
    • 流程
    1. 当请求的线程数小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程
    2. 当请求的线程数大于corePoolSize时,会把新提交的任务存入到workQueue里面排队等待。
    3. 当请求数量到达corePoolSize+workQueue的长度时,会把此时的线程池扩容到maximumPoolSize的数量
    4. 当请求超过workQueue的长度+maximumPoolSize的长度时,会让拒绝策略RejectedExecutionHandler 来处理这些请求
    • 以银行办办业务为例
      corePoolSize相当于现在开放的窗口(假定为2),
      maximumPoolSize银行能开放的最大窗口数量(假定为5),
      workQueue 候客区(假定为3),
      比如现在只有一个顾客来的时候,直接就给他办理业务此时size=1,
      当有三个顾客来的时候,因为此时业务窗口(corePoolSize)只有2,所以有一个人得进入候客区(workQueue)排队,
      当有6个顾客来时,此时需要处理的数量已经超过了(coresize+workQueue.size),此时银行需要临时开放其他窗口来给顾客办理业务,最大可以将所有窗口都开放,及开放窗口数量最大为maximumPoolSize
      如果此时来了11个顾客,此时请求的数量已经超过了最大开放的窗口(maximumPoolSize)+候客区(workQueue),网点已经不能再容纳了,此时就把其他来办理业务的人交给RejectedExecutionHandler来处理拒绝掉
      当人越来越少时,新开放的窗口已经空闲了,如果此时空闲时间超过keepAliveTime,就让这个窗口的营业员下班,关闭这个窗口,直到最后只剩下最开始的两个窗口(corePoolSize)

    四大拒绝策略(等待队列已经满了,再也塞不下新的任务,同时线程池中的线程数达到了最大线程数,无法继续为新任务服务)

    1. AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException
    2. CallerRunsPolicy:把任务回推给线程提交方让他自己执行(例如回推给main线程),此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
    3. DiscardPolicy:不能执行的任务将被删除
    4. DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

    线程池配置参考

    1. CPU 密集型
      CPU 密集的意思是该任务需要大量的运算,而没有阻塞,CPU 一直全速运行。
      CPU 密集型任务尽可能的少的线程数量,一般为 CPU 核数 + 1 个线程的线程池。
    2. IO 密集型
      由于 IO 密集型任务线程并不是一直在执行任务,可以多分配一点线程数,如 CPU * 2 。
      也可以使用公式:CPU 核数 / (1 - 阻塞系数);其中阻塞系数在 0.8 ~ 0.9 之间。。

    相关文章

      网友评论

          本文标题:线程池

          本文链接:https://www.haomeiwen.com/subject/wzdqyctx.html