线程池调度总览
线程池执行步骤
线程池七大参数
1.ThreadFactory 工厂类
创建线程的工厂类,用于创建线程(一般使用默认的)。
2.CorePoolSize 核心线程池
线程池核心线程数量,核心线程不会被回收,即使没有任务执行,也会保持空闲状态。
如果线程池中的线程少于此数目,则在执行任务时创建。
3.maximumPoolSize最大线程数
线程池允许容纳同时执行最大的线程数,当线程数量达到corePoolSize,且workQueue队列塞满任务了之后,继续创建线程。
corePoolSize + workQueue < maximumPoolSize,有任务时会继续创建线程。
4.BlockingQueue阻塞队列
当前线程数超过corePoolSize时,新的任务会处在等待状态,并存在workQueue中,BlockingQueue是一个先进先出的阻塞式队列实现,底层实现会涉及Java并发的AQS机制。
5.KeepAliveTime 存活时间
超过corePoolSize之后的“临时线程”的存活时间。
线程数量超过核心线程数时,空间时间超过KeepAliveTime,多余线程会被销毁直至剩下corePoolSize个线程为止。
6.Unit 时间单位
keepAliveTime的单位
7.RejectedExceptionHandler
线程池执行拒绝策略,当线数量达到maximumPoolSize,且workQueue也已经塞满了任务的情况下,线程池会调用handler拒绝策略来处理请求。
-
AbortPolicy:为线程池默认的拒绝策略,该策略直接抛异常处理。
-
DiscardPolicy:直接抛弃不处理。
-
DiscardOldestPolicy:丢弃队列中最老的任务。
-
CallerRunsPolicy:将任务分配给当前执行execute方法线程来处理。
-
自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可
-
将数据保存到数据,待系统空闲时再进行处理
-
将数据用日志进行记录,后由人工处理
-
配置最大线程数
分析任务特点(CPU密集型、IO密集型)
-
CPU密集型
-
需要大量CPU运算,没有阻塞,CPU会一直全速运行。
-
适用于多核CPU,单核CPU无法并发执行。
-
配置时尽可能减少线程数量,最大线程数 = CPU核数+1
-
-
IO密集型
-
需要大量的IO,会有大量的阻塞。
-
单线程执行IO密集型任务,会造成CPU的运算力浪费在等待上。IO密集型任务适用多线程,会加速任务运行。
-
配置公式:最大线程数=CPU核数/(1-阻塞系数) 阻塞系数在0.8~0.9之间
例如:8核CPU,最大线程数 = 8 / (1-0.9) = 80
-
线程池练习
核心线程数:10,队列大小:5,最大线程数:20
实例1:任务数量8,任务全部由核心线程池执行。
实例2:任务数量13,10个任务全部由核心线程池执行 + 3个任进入队列
实例3:任务数量18,核心线程池(10) + 队列 (5) + 新线程(3)
-
3个临时线程执行完毕,空闲时间达到KeepAliveTime时,线程退出,直到线程数量= corePoolSize。核心线程依旧在队列中,等待任务。
-
如果allowCoreThreadTimeout=true,则核心线程执行完毕后,空闲时间达到KeepAliveTime时,线程也退出,直到线程数量=0。
实例4:任务数量30:核心线程池(10) + 队列 (5) + 新线程(10) < 30
-
第一种情况:执行饱和策略,抛出异常 => AbortPolicy
-
第二种情况:直接抛弃多余的5个任务 => DiscardPolicy
-
第三种情况:实现RejectedExecutionHandler接口,利用日志处理、抛出消息等。