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

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。