[小笔记] 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 的危险,运用者运用起来就感觉网络特别的慢。