java 线程池解析 - Executors篇

参考文章: https://www.jianshu.com/p/210eab345423

什么是线程池

就是把线程用一个队列管理起来(池子), 需要用的时候从这里拿, 用完放回来, 避免野蛮的新起线程执行任务

为什么要线程池

1. 避免重复开销

线程的创建销毁是比较消耗资源的, 特别是如果执行时间还比创建销毁时间短, 就更加不划算了, 所以通过线程池来管理线程, 免去频繁的创建销毁带来的额外花销

2. 防止线程爆发

暴力的直接开线程执行任务, 如果这种代码多了, 很多线程同时创建执行, 很容易造成资源不够用, 从而导致一些异常发生

几种线程池创建的区别

Executors中就有一些线程池模板(也可以自己通过ThreadPoolExecutor来创建)

  • FixedThreadPool : 定长线程池, 使用LinkedBlockingQueue堆集的运行任务顺序执行

  • SingleThreadExecutor: 相当于FixedThreadPool的单线程版本

  • CachedThreadPool: 缓存线程池, 线程最大数为整形最大值, 过期时间60秒, 无核心线程, 使用同步队列SynchronousQueue(无空闲线程, 直接创建线程执行)

  • ScheduledThreadPool: 使用延时队列DelayQueue, 支持定时任务, 需要进来的执行任务实现Delayed接口

  • SingleThreadScheduledExecutor: ScheduledThreadPool的单线程版

也可以自定义线程池
自定义线程池

部分名词解释

  • corePoolSize: 核心线程数量, 默认是不会关闭的, 但如果指定了allowCoreThreadTimeOut=true , 则会根据keepAliveTime将空闲核心线程回收
  • maximumPoolSize: 最大线程数, 线程池中最多可以开启的线程数, 会根据keepAliveTime进行空闲线程回收
  • keepAliveTime: 最大空闲时间, 超过该时间的空闲非核心线程会被销毁(allowCoreThreadTimeOut=true时, 核心线程也会被销毁)
  • unit: keepAliveTime 的时间单位(具体枚举值下面列出)
  • workQueue: 任务队列, 存放需要自行的的任务(具体4中队列类型下面列出)
  • threadFactory: 线程创建工厂, 可以自定义线程名称什么的(一般很少用)
  • handler: 异常(一般很少用)

时间单位

  • NANOSECONDS : 1微毫秒 = 1微秒 / 1000
  • MICROSECONDS : 1微秒 = 1毫秒 / 1000
  • MILLISECONDS : 1毫秒 = 1秒 /1000
  • SECONDS : 秒
  • MINUTES : 分
  • HOURS : 小时
  • DAYS : 天

队列类型

  • SynchronousQueue: 这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即整型最大数

  • LinkedBlockingQueue: 这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize

  • ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误

  • DelayQueue: 队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

发布了74 篇原创文章 · 获赞 49 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_34208844/article/details/87088038