前言
多線程編程是 Java 開發者必須掌握的核心技能,而瞭解線程創建的不同方式及其內部機制,是構建高效穩定併發程序的基礎。本文將通過實例代碼、原理分析和源碼解讀,全面剖析 Java 中創建線程的四種主要方式,幫助開發者選擇最適合自己業務場景的線程創建方法。
一、繼承 Thread 類創建線程
1.1 基本原理
Thread 類是 Java 中表示線程的核心類,它實現了 Runnable 接口。通過繼承 Thread 類創建線程是最直接的方式,只需要重寫 run()方法。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getName() + "正在執行");
// 線程執行邏輯
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// 創建線程對象
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 設置線程名稱
thread1.setName("Thread-1");
thread2.setName("Thread-2");
// 啓動線程
thread1.start();
thread2.start();
}
}
1.2 源碼解析
當調用start()方法時,JVM 會為線程分配資源並調用start0()本地方法,最終導致run()方法在新線程中執行:
// Thread類的start()方法簡化版源碼
public synchronized void start() {
if (threadStatus != 0) throw new IllegalThreadStateException(); // 確保線程未啓動
group.add(this); // 添加到線程組
start0(); // 核心:調用本地方法啓動新線程
}
// 本地方法,由JVM實現
private native void start0();
1.3 注意事項
- 必須調用
start()方法而非直接調用run()方法,後者只會在當前線程中執行,不會創建新線程 - 一個 Thread 實例只能被啓動一次,多次調用會拋出 IllegalThreadStateException 異常
- 繼承 Thread 類後無法再繼承其他類,因為 Java 是單繼承的
二、實現 Runnable 接口創建線程
2.1 基本原理
Runnable 接口是 Java 多線程的核心接口,它只包含一個run()方法。實現該接口的類可以交給 Thread 執行。
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getName() + "正在執行");
// 線程執行邏輯
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// 創建Runnable實現類對象
MyRunnable myRunnable = new MyRunnable();
// 創建Thread對象,傳入Runnable實例
Thread thread1 = new Thread(myRunnable, "Thread-1");
Thread thread2 = new Thread(myRunnable, "Thread-2");
// 啓動線程
thread1.start();
thread2.start();
}
}
2.2 Lambda 表達式簡化
Java 8 後可以使用 Lambda 表達式簡化 Runnable 實現:
public class RunnableLambdaDemo {
public static void main(String[] args) {
// 使用Lambda表達式創建Runnable
Runnable task = () -> {
String threadName = Thread.currentThread().getName();
System.out.println("線程" + threadName + "開始執行");
for (int i = 0; i < 5; i++) {
System.out.println(threadName + ":" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 創建並啓動線程
new Thread(task, "Lambda-Thread-1").start();
new Thread(task, "Lambda-Thread-2").start();
}
}
2.3 Thread 與 Runnable 的關係
Thread 類其實是 Runnable 接口的實現類。當 Thread 接收一個 Runnable 參數時,內部會保存這個 Runnable 引用,並在自己的 run()方法中調用它:
// Thread類的部分源碼
public class Thread implements Runnable {
/* Runnable 對象,如果通過構造函數傳入 */
private Runnable target;
// 構造函數接收Runnable參數
public Thread(Runnable target) {
this.target = target;
}
// run方法實現
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
三、實現 Callable 接口配合 Future 獲取返回值
3.1 基本原理
Runnable 接口無法返回執行結果,也不能拋出受檢異常,而 Callable 接口克服了這些限制。它是一個泛型接口,泛型參數表示返回值類型。Future 接口則用於獲取異步計算結果。
import java.util.concurrent.*;
public class CallableDemo {
public static void main(String[] args) throws Exception {
// 創建Callable對象
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("線程" + Thread.currentThread().getName() + "開始計算");
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
Thread.sleep(10); // 模擬耗時操作
}
return sum;
}
};
// 使用Lambda簡化
Callable<Integer> lambdaTask = () -> {
System.out.println("Lambda線程" + Thread.currentThread().getName() + "開始計算");
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
Thread.sleep(5); // 模擬耗時操作
}
return sum;
};
// 創建FutureTask
FutureTask<Integer> futureTask1 = new FutureTask<>(task);
FutureTask<Integer> futureTask2 = new FutureTask<>(lambdaTask);
// 啓動線程
new Thread(futureTask1, "Future-1").start();
new Thread(futureTask2, "Future-2").start();
// 獲取結果(阻塞)
System.out.println("等待計算結果...");
Integer result1 = futureTask1.get(); // 阻塞直到計算完成
System.out.println("Future-1計算結果:" + result1);
// 設置超時時間
try {
Integer result2 = futureTask2.get(2, TimeUnit.SECONDS);
System.out.println("Future-2計算結果:" + result2);
} catch (TimeoutException e) {
System.out.println("計算超時!");
futureTask2.cancel(true); // 嘗試取消任務
}
}
}
3.2 FutureTask 狀態機制與 Future 的關係
FutureTask 是 Future 接口的具體實現類,同時也實現了 Runnable 接口,這使它既可以被 Thread 直接執行,也可以提交給 Executor。FutureTask 內部維護一個狀態機,用於追蹤任務執行狀態:
- NEW:初始狀態,任務尚未執行
- COMPLETING:任務已完成,結果正在設置
- NORMAL:任務正常完成
- EXCEPTIONAL:任務執行過程中拋出異常
- CANCELLED:任務被取消(未開始執行)
- INTERRUPTING:任務正在被中斷
- INTERRUPTED:任務已被中斷
3.3 FutureTask 與 Executor 關係
在實際應用中,FutureTask 通常與 ExecutorService 結合使用,而不是直接通過 Thread 啓動:
ExecutorService executor = Executors.newFixedThreadPool(2);
// 方式1:使用submit提交Callable
Future<Integer> future1 = executor.submit(() -> {
Thread.sleep(1000);
return 123;
});
// 方式2:創建FutureTask然後提交
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
Thread.sleep(1000);
return 456;
});
executor.submit(futureTask);
// 通過Future獲取結果
Integer result1 = future1.get();
Integer result2 = futureTask.get();
3.4 Future 接口的關鍵方法
Future 接口提供了多個方法來管理異步任務:
get()- 阻塞獲取結果,直到任務完成get(long timeout, TimeUnit unit)- 帶超時的阻塞獲取cancel(boolean mayInterruptIfRunning)- 嘗試取消任務isCancelled()- 檢查任務是否被取消isDone()- 檢查任務是否完成
四、使用 Executor 框架創建線程
4.1 基本原理
Executor 框架是 Java 5 引入的,它提供了一套高級的線程池管理 API,實現了線程與任務的解耦,並對創建和管理線程提供了規範化的控制。
import java.util.concurrent.*;
public class ExecutorDemo {
public static void main(String[] args) {
// 創建固定大小的線程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交Runnable任務
for (int i = 0; i < 5; i++) {
final int taskId = i;
executor.execute(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("任務" + taskId + "開始執行,線程名:" + threadName);
try {
// 模擬任務執行
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("任務" + taskId + "執行完成,線程名:" + threadName);
});
}
// 提交Callable任務並獲取Future
Future<Integer> future = executor.submit(() -> {
System.out.println("計算任務開始執行,線程名:" + Thread.currentThread().getName());
Thread.sleep(2000);
return 123;
});
try {
System.out.println("計算結果:" + future.get());
} catch (Exception e) {
e.printStackTrace();
}
// 關閉線程池
executor.shutdown();
// 等待線程池終止(生產環境需要更優雅的處理)
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
4.2 ThreadPoolExecutor 核心參數詳解
ThreadPoolExecutor 是線程池的核心實現類,它有 7 個關鍵參數:
-
corePoolSize:核心線程數
- 線程池中長期保持的線程數量
- CPU 密集型任務建議設為:
Runtime.getRuntime().availableProcessors() - IO 密集型任務建議設為:
Runtime.getRuntime().availableProcessors() * 2或更高
-
maximumPoolSize:最大線程數
- 線程池允許創建的最大線程數
- 當工作隊列滿時,會創建臨時線程直到達到最大線程數
-
keepAliveTime:線程存活時間
- 臨時線程(超過核心線程數的線程)的空閒存活時間
-
workQueue:工作隊列
- ArrayBlockingQueue:有界隊列,容量固定,適合任務數量可預測的場景
- LinkedBlockingQueue:默認無界隊列,可能導致內存溢出,需謹慎使用
- SynchronousQueue:無容量隊列,提交任務必須有線程立即處理
- PriorityBlockingQueue:優先級隊列,可對任務排序
-
threadFactory:線程工廠
- 用於創建和定製化線程(如命名、設置優先級等)
-
rejectedExecutionHandler:拒絕策略
- AbortPolicy:默認策略,拒絕任務時拋出 RejectedExecutionException
- CallerRunsPolicy:由提交任務的線程自己執行該任務(適合主線程提交任務的突發流量場景,自我調節)
- DiscardPolicy:直接丟棄任務,不拋出異常(適合允許丟棄任務的場景)
- DiscardOldestPolicy:丟棄隊列頭部(最舊)的任務,然後嘗試執行當前任務(適合新任務優先的場景)
-
allowCoreThreadTimeOut:是否允許核心線程超時
- 默認 false,設為 true 時核心線程也會受 keepAliveTime 限制
4.3 任務類型與線程池參數調優
不同類型的任務需要不同的線程池配置:
// CPU密集型任務線程池(假設8核CPU)
int cpuCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor cpuIntensivePool = new ThreadPoolExecutor(
cpuCores, // 核心線程等於CPU核心數
cpuCores, // 最大線程等於CPU核心數
0L, TimeUnit.MILLISECONDS, // 非核心線程立即回收
new LinkedBlockingQueue<>(1000), // 有界隊列避免OOM
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()); // 主線程執行,起到反饋調節作用
// IO密集型任務線程池(假設任務平均IO等待時間佔比80%)
// 最佳線程數 = 核心數 / (1 - IO阻塞時間佔比)
int optimalThreads = (int)(cpuCores / (1 - 0.8));
ThreadPoolExecutor ioIntensivePool = new ThreadPoolExecutor(
optimalThreads, // 核心線程設為最佳線程數
optimalThreads * 2, // 最大線程數可以更大
60L, TimeUnit.SECONDS, // 允許空閒線程存活一段時間
new ArrayBlockingQueue<>(5000), // 有界隊列
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
// 短時任務線程池(執行時間短,提交頻率高)
ThreadPoolExecutor shortTaskPool = new ThreadPoolExecutor(
10, // 保持一定數量的核心線程
200, // 允許更多臨時線程
10L, TimeUnit.SECONDS, // 臨時線程較快回收
new SynchronousQueue<>(), // 直接傳遞隊列,無隊列緩衝
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()); // 拒絕策略可視情況選擇
4.4 常見的線程池類型及隱患
-
FixedThreadPool:固定大小線程池
ExecutorService fixedPool = Executors.newFixedThreadPool(5);隱患:使用無界隊列 LinkedBlockingQueue,隊列可能無限增長導致 OOM
-
CachedThreadPool:可緩存線程池,適合短期異步任務
ExecutorService cachedPool = Executors.newCachedThreadPool();隱患:最大線程數為 Integer.MAX_VALUE,可能創建大量線程導致資源耗盡
-
SingleThreadExecutor:單線程執行器,適合順序執行任務
ExecutorService singlePool = Executors.newSingleThreadExecutor();隱患:同樣使用無界隊列,可能堆積大量任務
-
ScheduledThreadPoolExecutor:支持定時和週期任務
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3); // 延遲執行 scheduledPool.schedule(() -> System.out.println("延遲3秒執行"), 3, TimeUnit.SECONDS); // 週期執行(固定速率) scheduledPool.scheduleAtFixedRate(() -> System.out.println("每2秒執行一次"), 0, 2, TimeUnit.SECONDS); // 週期執行(固定延遲) scheduledPool.scheduleWithFixedDelay(() -> System.out.println("上一次執行完成後延遲1秒再執行"), 0, 1, TimeUnit.SECONDS);
4.5 拒絕策略詳解及應用場景
-
AbortPolicy(默認):
new ThreadPoolExecutor.AbortPolicy()- 行為:直接拋出 RejectedExecutionException 異常
- 適用場景:任務必須執行成功,且需要立即感知失敗的情況
- 實例:訂單處理系統,拒絕後可立即向用户反饋"系統繁忙"
-
CallerRunsPolicy:
new ThreadPoolExecutor.CallerRunsPolicy()- 行為:將任務回退給提交任務的線程執行
- 適用場景:主線程提交任務,可接受主線程暫時阻塞的情況
- 實例:Web 服務器主線程提交請求處理任務,當線程池滿時主線程自己處理,減緩請求接收速度,形成反饋調節
-
DiscardPolicy:
new ThreadPoolExecutor.DiscardPolicy()- 行為:靜默丟棄任務,不做任何處理
- 適用場景:任務可丟棄,且不需要通知
- 實例:日誌記錄、監控數據收集等非關鍵任務
-
DiscardOldestPolicy:
new ThreadPoolExecutor.DiscardOldestPolicy()- 行為:丟棄隊列頭部(等待最久)的任務,然後嘗試執行當前任務
- 適用場景:新任務比舊任務重要的場景
- 實例:實時數據處理,新數據比舊數據更有價值
-
自定義拒絕策略:
new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 自定義處理邏輯,如記錄日誌後丟棄 logger.warn("任務被拒絕: " + r.toString()); // 或放入備用隊列 backupQueue.offer(r); } }
4.6 自定義線程池
生產環境中,應避免直接使用 Executors 工廠方法,而是自定義 ThreadPoolExecutor:
import java.util.concurrent.*;
public class CustomThreadPoolDemo {
public static void main(String[] args) {
// 創建自定義線程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心線程數
5, // 最大線程數
60, TimeUnit.SECONDS, // 空閒線程存活時間
new ArrayBlockingQueue<>(10), // 有界工作隊列
new ThreadFactory() { // 自定義線程工廠
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("CustomThread-" + count++);
return t;
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略:調用者運行
);
// 監控線程池狀態
ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor();
monitor.scheduleAtFixedRate(() -> {
System.out.println("=== 線程池狀態 ===");
System.out.println("活躍線程數: " + executor.getActiveCount());
System.out.println("核心線程數: " + executor.getCorePoolSize());
System.out.println("最大線程數: " + executor.getMaximumPoolSize());
System.out.println("線程池大小: " + executor.getPoolSize());
System.out.println("隊列任務數: " + executor.getQueue().size());
System.out.println("================");
}, 0, 5, TimeUnit.SECONDS);
// 提交任務
for (int i = 0; i < 15; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println("任務" + taskId + "由線程" +
Thread.currentThread().getName() + "執行");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// 關閉線程池
executor.shutdown();
monitor.shutdown();
}
}
4.7 優雅關閉線程池
在生產環境中,關閉線程池需要更加謹慎:
public static void shutdownPoolGracefully(ExecutorService pool) {
pool.shutdown(); // 停止接收新任務
try {
// 等待已提交任務執行完畢
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
// 取消當前執行的任務
pool.shutdownNow();
// 等待任務響應中斷
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("線程池未能完全關閉");
}
}
} catch (InterruptedException ie) {
// 重新取消當前線程的所有任務
pool.shutdownNow();
// 保留中斷狀態
Thread.currentThread().interrupt();
}
}
五、線程異常處理對比
各種創建線程方式處理異常的方式有所不同:
5.1 Thread 和 Runnable 的異常處理
public class ThreadExceptionDemo {
public static void main(String[] args) {
// 設置默認未捕獲異常處理器
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
System.out.println("線程" + t.getName() + "發生異常:" + e.getMessage());
});
// 創建線程並設置線程專屬的異常處理器
Thread thread = new Thread(() -> {
throw new RuntimeException("測試異常");
}, "ExceptionThread");
thread.setUncaughtExceptionHandler((t, e) -> {
System.out.println("線程" + t.getName() + "的專屬處理器捕獲異常:" + e.getMessage());
});
thread.start();
}
}
5.2 Future 異常處理
public class FutureExceptionDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
throw new RuntimeException("Callable異常測試");
});
try {
Integer result = future.get();
} catch (InterruptedException e) {
System.out.println("任務被中斷");
} catch (ExecutionException e) {
System.out.println("任務執行異常:" + e.getCause().getMessage());
}
executor.shutdown();
}
}
六、四種方式全面對比
下面通過表格對比這四種創建線程的方式:
| 創建方式 | 支持返回值 | 線程複用 | 異常處理方式 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|---|---|
| Thread 類 | 否 | 否 | UncaughtExceptionHandler | 簡單直觀 | 無法繼承其他類;無法重用線程 | 簡單場景,學習入門 |
| Runnable 接口 | 否 | 否 | UncaughtExceptionHandler | 可以繼承其他類;多個線程可共享一個任務 | 無法直接獲取返回值 | 任務線程分離,無返回值場景 |
| Callable+Future | 是 | 否 | Future.get()捕獲 ExecutionException | 可獲取返回值;可拋出受檢異常;支持取消和超時 | 使用較複雜;獲取結果阻塞 | 需要獲取任務執行結果的場景 |
| Executor 框架 | 是(Callable) | 是(線程池) | 線程池拒絕策略;Future 處理 | 線程池複用;任務調度靈活;資源管理優化 | 創建配置較複雜 | 生產環境,高併發場景 |
七、實際應用場景分析
7.1 Web 應用中的異步處理
@RestController
public class AsyncProcessController {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
// 線程安全的結果存儲
private static final ConcurrentHashMap<String, Future<Result>> resultStorage =
new ConcurrentHashMap<>();
@PostMapping("/process")
public String processRequest(@RequestBody Request request) {
// 提交異步任務並返回標識
Future<Result> future = executor.submit(() -> {
// 模擬耗時處理
Thread.sleep(5000);
return new Result("處理完成: " + request.getData());
});
// 將Future存儲,供後續查詢
resultStorage.put(request.getId(), future);
return "請求已提交,ID: " + request.getId();
}
@GetMapping("/result/{id}")
public String getResult(@PathVariable String id) {
Future<Result> future = resultStorage.get(id);
if (future == null) {
return "未找到對應請求";
}
if (future.isDone()) {
try {
Result result = future.get();
// 任務完成後從存儲中移除,避免內存泄漏
resultStorage.remove(id);
return "處理結果: " + result.getMessage();
} catch (Exception e) {
return "處理出錯: " + e.getMessage();
}
} else {
return "處理中...";
}
}
// 應用關閉時
@PreDestroy
public void destroy() {
shutdownPoolGracefully(executor);
}
}
7.2 並行計算性能對比
以下是一個簡單的性能對比測試:
public class ThreadPerformanceCompare {
private static final int TASK_COUNT = 10000;
private static final int THREAD_COUNT = 100;
public static void main(String[] args) throws Exception {
// 測試直接創建線程
long start1 = System.currentTimeMillis();
testDirectThreads();
long time1 = System.currentTimeMillis() - start1;
// 測試線程池
long start2 = System.currentTimeMillis();
testThreadPool();
long time2 = System.currentTimeMillis() - start2;
System.out.println("直接創建線程耗時:" + time1 + "ms");
System.out.println("使用線程池耗時:" + time2 + "ms");
System.out.println("性能提升:" + (time1 - time2) * 100.0 / time1 + "%");
}
private static void testDirectThreads() throws Exception {
final CountDownLatch latch = new CountDownLatch(TASK_COUNT);
for (int i = 0; i < TASK_COUNT; i++) {
new Thread(() -> {
try {
// 模擬任務執行
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown();
}
}).start();
}
latch.await();
}
private static void testThreadPool() throws Exception {
final CountDownLatch latch = new CountDownLatch(TASK_COUNT);
// 線程池核心線程數設為THREAD_COUNT
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
for (int i = 0; i < TASK_COUNT; i++) {
executor.execute(() -> {
try {
// 模擬任務執行
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown();
}
});
}
latch.await();
executor.shutdown();
}
}
性能差異説明:
- 線程池的性能優勢主要來自於避免了線程頻繁創建和銷燬的開銷
- 每創建一個線程大約需要 1MB 的內存空間,且線程上下文切換也有開銷
- 本測試使用簡單任務(sleep 1ms),這種情況下線程創建開銷比任務執行開銷大得多,性能差異被放大
- 實際生產中,應根據任務複雜度和執行時間特點進行專門的性能測試,並據此調整線程池參數
總結
本文深入剖析了 Java 中創建線程的四種方式:繼承 Thread 類、實現 Runnable 接口、實現 Callable 接口和使用 Executor 框架。通過實例代碼、源碼解析和性能對比,我們可以得出以下幾點結論:
- 簡單任務:對於簡單場景,Runnable 接口配合 Lambda 表達式是最簡潔的方式
- 需要返回值:使用 Callable+Future 可以獲取異步計算結果
- 生產環境:幾乎所有生產環境都應該使用 Executor 框架管理線程資源
- 異常處理:不同方式的異常處理機制不同,需要針對性設計
- 性能考慮:線程創建和銷燬開銷大,池化複用能顯著提升性能
在實際開發中,推薦遵循以下原則:
- 優先使用高級併發工具而非直接操作線程
- 自定義線程池參數,避免使用 Executors 工廠方法的隱患
- 根據任務特性(CPU 密集型/IO 密集型)選擇合適的線程池大小
- 使用有界隊列防止內存溢出,配合合理的拒絕策略
- 妥善處理線程異常,防止任務靜默失敗
- 優雅關閉線程池,避免資源泄露
掌握這四種線程創建方式及其適用場景,是 Java 多線程編程的重要基礎,也是構建高性能併發應用的第一步。
在下一篇文章中,我們將深入探討線程生命週期與基礎操作。敬請期待!
感謝您耐心閲讀到這裏!如果覺得本文對您有幫助,歡迎點贊 👍、收藏 ⭐、分享給需要的朋友,您的支持是我持續輸出技術乾貨的最大動力!
如果想獲取更多 Java 技術深度解析,歡迎點擊頭像關注我,後續會每日更新高質量技術文章,陪您一起進階成長~