线程池都经常用,但是具体的参数和具体的参数设置一定要知道,否会任务拒绝或者多线程上下文切换频繁;

高并发尽量不要用java提供的FixedThreadPool和SingleThreadExecutor ,直接用ThreadPoolExecutor自己定义参数,合理的配置参数。

通用的设置:
* 具体的参数设置需要根据几个值来决定
            - tasks :希望每秒能执行的任务数
            - taskcost:平均每个任务花费时间(包含cpu轮转的时间)
            - responsetime:系统允许容忍的最大响应时间
        * 做几个计算
            - corePoolSize   核心处理线程
                * threadcount = tasks/(1/taskcost) =tasks*taskcout 。corePoolSize设置应该大于最小值
                * 根据8020原则,取最大值的80%
            - queueCapacity = (coreSizePool/taskcost)*responsetime
                * 计算可得 queueCapacity 。超过了的需要新开线程来执行
                * 切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。
            - maxPoolSize  最大线程数
                * 计算可得 maxPoolSize =(max(tasks)- queueCapacity)/(1/taskcost)
                * (最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数
            - rejectedExecutionHandler:拒绝策略根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
            - keepAliveTime和allowCoreThreadTimeout,超时等待时间采用默认通常能满足

 

正常情况下,线程过多的时候会引发线程切换,会有CPU轮转的时间被浪费掉。

如果不知道额参数的话,将CPU的利用率最大化:

        * CPU密集型任务应配置尽可能小的线程,如配置Ncpu+1个线程的线程池。由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*Ncpu。

        * 混合型的任务,如果可以拆分,将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐量将高于串行执行的吞吐量。如果这两个任务执行时间相差太大,则没必要进行分解。可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。

       * 对于IO型的任务的最佳线程数,有个公式可以计算

        Nthreads = NCPU * UCPU * (1 + W/C)

        其中:

        * NCPU是处理器的核的数目

        * UCPU是期望的CPU利用率(该值应该介于0和1之间)

        * W/C是等待时间与计算时间的比率