对于线程池的理解

2020-09-06  本文已影响0人  倚仗听江

线程池的作用:控制线程的数量,处理过程中把任务放到队列中,然后在线程创建后启动这些任务。如果线程数量超过了最大数量,超出的线程等待。等到其他线程执行完毕后,再从队列中取出任务来执行。

线程池的作用:

有Java为我们提供了这样三种直接创建线程池的方法,但不推荐使用。因为如果使用这些方式,在出现问题的时候,不容易快速定位到底是哪个线程出的问题。而且它们的任务队列都是LinkedBlockingQueue,这是由链表结构组成的有界(但默认值大小为Integer.MAX_VALUE)阻塞队列。

ExecutorService pool1 = Executors.newSingleThreadExecutor();//一池一线程
ExecutorService pool2 = Executors.newFixedThreadPool(5);//一池五线程
ExecutorService pool3 = Executors.newCachedThreadPool();//一池N线程

顺便提一下阻塞队列吧

当阻塞队列是空的时候,从队列中获取元素的操作会被阻塞;
​当阻塞队列是满的时候,往队列中添加元素的操作会被阻塞。

阻塞队列的种类

线程池的七大参数:

  1. corePoolSize:线程池中常驻的核心线程数
  2. maxiumPoolSize:能够容纳的最大线程数,必须大于等于1。
  3. keepAliveTime:多余空闲线程的存活时间。当前线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁直到只剩下corePoolSize个线程位置。
  4. unit:keepAliveTime的单位
  5. workQueue:任务队列,被提交但未被执行的任务
  6. threadFactory:生成线程池中工作线程的线程工厂,用于创建线程,默认即可。
  7. handler:拒绝策略,表示当队列满了并且工作线程大于等于最大线程数时,如何拒绝请求。

线程池的工作原理:

  1. 在创建好线程池后,等待提交过来的任务请求
  2. 当调用execute方法添加一个请求任务时,线程池就会做以下判断
    2.1 如果当前运行的线程数量少于corePoolSize,那么马上创建线程运行这个任务
    2.2 如果当前运行的线程数量大于等于corePoolSize,那么将这个任务放进任务队列
    2.3 如果当前任务队列已经满了但是当前运行的线程数量少于maxiumPoolSize,那么就要立即创建非核心线程运行这个任务
    2.4 如果当前任务队列满了并且正在运行的线程数量大于等于maxiumPoolSize,那么线程池就会启动饱和拒绝策略
  3. 当一个线程完成任务后,它会从队列中取下一个任务来执行
  4. 当一个线程无事可做超过一定时间(keepAliveTime),线程池就会判断:如果当前运行的线程数大于corePoolSize,那么这个线程就会被停掉。所以线程池所有任务完成之后,最终会收缩到corePoolSize的大小。

拒绝策略:

当达到最大线程数且等待队列满时,就要启用拒绝策略。

  1. AbortPolicy(默认):直接抛出RejectedException。
  2. CallerRunsPolicy:不会抛弃任务也不会抛出异常,而是回退给调用者
  3. DiscardOldestPolicy:丢弃等待最久的任务。
  4. DiscardPolicy:直接丢弃任务,不做任何处理。

如何合理配置线程数

看是CPU密集型任务还是IO密集型任务

System.out.println(Runtime.getRuntime().availableProcessors());//查看核心数

CPU密集型:CPU核心数 + 1

IO密集型:

  1. CPU核心数 * 2 (IO密集型不是一直在执行任务,所以应该多配置些线程)
  2. CPU核心数/(1 - 阻塞系数) (阻塞系数一般为0.8~0.9)
上一篇 下一篇

猜你喜欢

热点阅读