[小笔记] Java 线程池

除了 newScheduledThreadPool 创建的线程池,其他的默认线程池都是以 ThreadPoolExecutor 对象实现的。

1 默认线程池的实现

1.1 FixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }

1.2 SingleThreadPool

public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }

1.3 CachedThreadPool

public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }

2 ThreadPoolExecutor

2.1 CorePoolSize

核心线程数。当目前的线程数小于设置的核心线程数时,有新的任务来时会直接创建一个新的线程来执行任务,就算当前有 Idel 的线程也会创建;当当前的线程数大于等于核心线程数时,就会把任务加入等待队列(后边说)。

  • 核心线程可以在创建线程池时直接创建,而不用等待运行时创建
  • 核心线程默认是不会回收的,可以通过设置参数让其 Idel 一段时间后让其回收

2.2 MaximumPoolSize

最大线程数。MaximumPoolSize - CorePoolSize 就是普通线程数。当核心线程数和等待队列都满的时候,但是最大线程数没有满,就会创建非核心线程执行;最大线程数满的时候就会触发拒绝策略。(后边说)
根据 KeepAliveTime 参数,禁止一段时间后会回收(也可以不回收)。

2.3 KeepAliveTime

非核心线程回收间隔时间。当非核心线程 Idel 后,超过该设置时间就会被回收,如果想不被回收需要把超时时间设置为 Long.MAX

2.4 WorkQueue

任务队列。当核心线程数满的时候存放等待的任务,当线程空闲时按顺序递交任务给线程执行。
下面列举一些有代表性的 Queue。

2.4.1 LinkedBlockingQueue

无限制等待任务队列的大小,也就是说核心线程数设置不为0的情况下,非核心线程是不会创建的。

2.4.2 SynchronousQueue

等待线程的大小为0,直接递交任务给 Thread 执行。

2.4.3 ArrayBlockingQueue

可以设置等待任务队列的大小

2.5 拒绝策略

2.5.1 AbortPolicy

默认策略,直接抛出异常。

2.5.2 DiscardPolicy

直接丢弃当前任务。

2.5.3 DiscardOldestPolicy

丢弃一个队列中最旧的任务。

2.5.4 CallerRunsPolicy

直接在提交任务的线程执行这个任务。

2.6 总结

提交一个任务的不同情况分析:

2.6.1 核心线程数有空闲

如果核心线程数没有满,创建新的线程执行;如果核心线程数满了,但是有 Idel 的核心线程,直接用 Idel 的核心线程执行。

2.6.2 核心线程已满,但任务队列不满

将任务加入到队列中,等有线程空闲了,从队列中取任务执行。

2.6.3 核心线程和任务队列都已满,但未达到最大线程数

创建非核心线程执行任务。

2.6.4 所有都达到上限

执行拒绝策略。

3 最后

LinkedBlockingQueue 是有 OOM 风险的,当任务过于多时都会堆积在 Queue 中,导致 OOM。这也是为什么有的公司禁止使用 SingleThreadPool 和 FixedThreadPool,不过一般客户端都还好,主要是服务端。
我在开发中还发现有大聪明把 OkHttp 的线程池设置为以下这样:

val executor = ThreadPoolExecutor( 0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, LinkedBlockingQueue() )

导致网络请求只在一个线程中执行,大部分的网络请求任务都在 WorkQueue 中等待,而且还有 OOM 的风险,使用者使用起来就感觉网络特别的慢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值