【連載 01】併發與並行

FunTester發表於2024-11-25

本章將會介紹 Java 多執行緒併發程式設計的入門知識,從 Java 多執行緒常用實現開始,由淺入深瞭解 Java 兩種常用的執行緒池建立使用及其適用場景。透過對 java.util.concurrent.ThreadPoolExecutor 原始碼的解析,瞭解自定義 Java 執行緒池的幾個重要引數,並掌握執行緒池內在的執行邏輯,達到自定義 Java 執行緒池的目的。

併發與並行

在進行 Java 多執行緒程式設計之前,首先分享一個這個概念:併發和並行。

這兩個概念在實際工作很少去刻意區分,屬於非常基礎的知識。如果你想了解 Java 多執行緒程式設計,就必需先搞清楚這兩個概念以及差異。

併發 (Concurrency) 和並行 (Parallelism) 都是指同時處理多個事務的能力,但是這兩個概念本質上還是有差異的。總結來說並行指的是時間上的同時發生,而併發並不一定是。如果站在觀察者角度來看,併發看起來很像並行。

要想更好地理解,小故事是無法避免的,下面請讓聽一聽我這個 “超市結賬” 版本。

這裡有一家叫 “小八” 的超市,裡面只有一個收銀臺,但是確有兩個收銀通道。平時空閒的時候只開放一條收銀通道,人多的時候開發兩條收銀通道,讓所有顧客更快完成結賬付款,減少等待時間。

但實際情況是這樣的,只有一位收銀員,但是收銀臺對於顧客是黑盒,顧客完全無法瞭解收銀臺裡面如何執行,更無法知道真相:只有一位收銀員。

對於單個顧客,他們結賬流程是:1. 把商品挨個掃描計價;2. 計算顧客應付金額;3. 顧客付款;4. 顧客收拾商品結束購物。

當空閒的時候,每個顧客結賬過程大約需要 1 分鐘。當繁忙的時候,開放兩條通道,平均每個顧客結賬也需要 1 分鐘。乍一看,收銀臺的效能提升了 1 倍。

實際情況是這樣的:這位收銀員,一邊等待第一條通道顧客出示付款碼,一邊給第二條通道的顧客掃描計價;一邊等待第一條通道的顧客自己打包商品,一邊再給第二條通道的顧客找零錢。如圖 1-1 所示:

圖 1-1 併發收銀臺

這個小故事裡面,超市相當於我們的計算機,收銀臺或者收銀員相當於 CPU。當我們只有一顆 CPU 時,依然可以同時處理兩條結賬通道的顧客。這裡的通道相當於執行緒。原來 1 分鐘只能完成一個結賬週期,透過增加結賬通道提升了 1 倍的效能。

如果你站在顧客的視角,兩條通道顧客在同時結賬,這個就叫做併發。如果超市老闆又招聘了一位收銀員,兩位收銀員分別處理兩條結賬通道,兩條通道相互不影響,這個就叫做並行。如圖 1-2 所示:

圖 1-2 並行收銀臺

對於 CPU 來說,程式就相當於是超市結賬的顧客,所以在使用 Java 進行效能測試中,我們關心更多的就是併發。

併發和並行是電腦科學中兩個密切相關但概念上不同的術語,主要用於描述任務的執行方式。

特徵總結:

特性 併發(Concurrency) 並行(Parallelism)
定義 多個任務交替執行,體現為任務之間的協作與排程,側重任務切換 多個任務同時執行,強調同時性,利用多核或多處理器資源。
執行單位 任務可以在單核或多核上透過時間片輪轉執行(分時共享)。 任務必須在多核、多執行緒或多處理器上同時執行。
特點 - 更注重任務的邏輯結構(任務可以部分完成)。
- 強調程式的設計能力,避免競態條件。
- 強調硬體能力,要求硬體支援同時執行。
- 提升任務吞吐量。
典型場景 - 多工處理:如在 GUI 中,UI 響應使用者互動的同時處理後臺資料更新。
- 非同步 I/O 操作。
- 科學計算:大規模矩陣計算、影像處理等。
- 並行資料處理,如 MapReduce、GPU 運算。
硬體要求 不需要依賴多核,多執行緒環境即可實現。 需要依賴多核、多處理器或 GPU。
技術示例 - Java 的執行緒池(如 Executor)。
- Golang 的 Goroutines(協程)。
- CUDA 的 GPU 程式設計。
- OpenMP 多執行緒計算。
關鍵問題 如何設計任務的交替邏輯,避免死鎖、資源競爭。 如何分配任務到多個計算單元,最大化硬體利用率。

書的名字:從 Java 開始做效能測試

如果本書內容對你有所幫助,希望各位多多讚賞,讓我可以貼補家用。讚賞兩位數可以提前閱讀未公開章節。我也會嘗試製作本書的影片教程,包括必要的答疑。

FunTester 原創精華
  • 混沌工程、故障測試、Web 前端
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go
  • 白盒、工具、爬蟲、UI 自動化
  • 理論、感悟、影片
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援
暫無回覆。

相關文章