面試官:創(chuàng)建線程池的幾種方式以及區(qū)別
創(chuàng)建線程池有多種方式,主要通過(guò) Java 的 java.util.concurrent 包提供的 Executors 工具類來(lái)實(shí)現(xiàn)。以下是幾種常見(jiàn)的線程池類型及其區(qū)別:
1. FixedThreadPool
//創(chuàng)建一個(gè)固定大小的線程池,模擬提交 10 個(gè)任務(wù)到線程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolExample {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); // 創(chuàng)建一個(gè)具有3個(gè)線程的固定線程池
for (int i = 1; i <= 10; i++) {
final int task = i;
fixedThreadPool.execute(() -> {
System.out.println("執(zhí)行任務(wù) " + task + ",線程:" + Thread.currentThread().getName());
});
}
fixedThreadPool.shutdown();
}
}
- 特點(diǎn):創(chuàng)建一個(gè)固定大小的線程池,池中始終保持指定數(shù)量的線程。
- 適用場(chǎng)景:適用于固定并發(fā)數(shù)的任務(wù),比如定量的短期并發(fā)任務(wù)。
- 優(yōu)點(diǎn):能夠有效地控制線程數(shù)量,避免資源消耗過(guò)多。
- 缺點(diǎn):如果所有線程都在執(zhí)行任務(wù),而新的任務(wù)不斷提交,可能會(huì)造成等待隊(duì)列過(guò)長(zhǎng)。
2. CachedThreadPool
//創(chuàng)建一個(gè)緩存線程池來(lái)處理任務(wù),模擬并發(fā)執(zhí)行 10 個(gè)任務(wù)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPoolExample {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 1; i <= 10; i++) {
final int task = i;
cachedThreadPool.execute(() -> {
System.out.println("執(zhí)行任務(wù) " + task + ",線程:" + Thread.currentThread().getName());
});
}
cachedThreadPool.shutdown();
}
}
- 特點(diǎn):創(chuàng)建一個(gè)可以根據(jù)需要自動(dòng)擴(kuò)展的線程池,當(dāng)線程空閑 60 秒后會(huì)被回收。
- 適用場(chǎng)景:適合執(zhí)行大量耗時(shí)較短的異步任務(wù)。
- 優(yōu)點(diǎn):線程數(shù)量不受限制(受系統(tǒng)資源限制),對(duì)于任務(wù)短小、并發(fā)量大但不穩(wěn)定的場(chǎng)景效果較好。
- 缺點(diǎn):如果任務(wù)增長(zhǎng)過(guò)快,會(huì)創(chuàng)建大量線程,可能會(huì)造成 OOM(Out of Memory)異常。
3. SingleThreadExecutor
//創(chuàng)建一個(gè)單線程線程池,順序執(zhí)行多個(gè)任務(wù)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutorExample {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 5; i++) {
final int task = i;
singleThreadExecutor.execute(() -> {
System.out.println("執(zhí)行任務(wù) " + task + ",線程:" + Thread.currentThread().getName());
});
}
singleThreadExecutor.shutdown();
}
}
- 特點(diǎn):創(chuàng)建單線程化的線程池,始終只有一個(gè)工作線程。
- 適用場(chǎng)景:適用于需要保證任務(wù)順序執(zhí)行的場(chǎng)景,避免多線程并發(fā)的復(fù)雜性。
- 優(yōu)點(diǎn):可以保證任務(wù)按順序執(zhí)行,適合單一任務(wù)隊(duì)列。
- 缺點(diǎn):性能較低,不適合需要高并發(fā)的場(chǎng)景。
4. ScheduledThreadPool
//創(chuàng)建一個(gè)支持定時(shí)和周期性執(zhí)行任務(wù)的線程池,示例任務(wù)每隔 2 秒執(zhí)行一次,共執(zhí)行 3 次。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExample {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2); // 創(chuàng)建一個(gè)有2個(gè)線程的定時(shí)線程池
scheduledThreadPool.scheduleAtFixedRate(() -> {
System.out.println("定時(shí)任務(wù)執(zhí)行,線程:" + Thread.currentThread().getName());
}, 0, 2, TimeUnit.SECONDS); // 0秒延遲后開(kāi)始,每隔2秒執(zhí)行一次任務(wù)
// 程序運(yùn)行5秒后關(guān)閉線程池
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduledThreadPool.shutdown();
}
}
- 特點(diǎn):創(chuàng)建一個(gè)支持定時(shí)或周期性任務(wù)執(zhí)行的線程池。
- 適用場(chǎng)景:適合執(zhí)行定時(shí)任務(wù)或周期性任務(wù),比如定時(shí)器、定時(shí)檢查等。
- 優(yōu)點(diǎn):可以方便地實(shí)現(xiàn)周期性任務(wù)管理。
- 缺點(diǎn):對(duì)高并發(fā)任務(wù)的處理能力較弱,通常用于任務(wù)量不大的場(chǎng)景。
5. WorkStealingPool(Java 8 引入)
//創(chuàng)建一個(gè)基于任務(wù)分解的線程池來(lái)并行執(zhí)行多個(gè)任務(wù),適合處理需要拆分的小任務(wù)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WorkStealingPoolExample {
public static void main(String[] args) throws InterruptedException {
ExecutorService workStealingPool = Executors.newWorkStealingPool(); // 創(chuàng)建默認(rèn)線程數(shù)為CPU核心數(shù)的工作竊取線程池
for (int i = 1; i <= 8; i++) {
final int task = i;
workStealingPool.submit(() -> {
System.out.println("執(zhí)行任務(wù) " + task + ",線程:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 讓主線程等待子任務(wù)執(zhí)行完成
workStealingPool.awaitTermination(3, TimeUnit.SECONDS);
workStealingPool.shutdown();
}
}
- 特點(diǎn):基于 ForkJoinPool 實(shí)現(xiàn),適用于大任務(wù)拆分成小任務(wù)的并行處理。線程數(shù)默認(rèn)為處理器核心數(shù)。
- 適用場(chǎng)景:適合處理較為復(fù)雜的并行任務(wù),比如分治算法。
- 優(yōu)點(diǎn):通過(guò)“工作竊取”算法實(shí)現(xiàn)任務(wù)的動(dòng)態(tài)負(fù)載均衡,能夠有效提升多核 CPU 的利用率。
- 缺點(diǎn):由于線程數(shù)不固定,可能對(duì)資源使用較多,不適合所有應(yīng)用。
區(qū)別總結(jié)
線程池類型 | 線程數(shù)量控制 | 特點(diǎn) | 適用場(chǎng)景 |
FixedThreadPool | 固定數(shù)量 | 固定線程數(shù),適合穩(wěn)定的任務(wù)并發(fā) | 固定并發(fā)任務(wù) |
CachedThreadPool | 自動(dòng)擴(kuò)展 | 動(dòng)態(tài)擴(kuò)展,空閑線程自動(dòng)回收,適合任務(wù)短小但并發(fā)量不穩(wěn)定 | 短期的異步并發(fā)任務(wù) |
SingleThreadExecutor | 單一線程 | 單線程順序執(zhí)行任務(wù),保證順序 | 順序執(zhí)行的任務(wù) |
ScheduledThreadPool | 可控核心線程數(shù) | 支持定時(shí)或周期性任務(wù) | 定時(shí)任務(wù)、周期性任務(wù) |
WorkStealingPool | 默認(rèn) CPU 核數(shù) | 基于任務(wù)拆分并行處理,提高多核 CPU 利用率 |