天天看點

java多線程為什麼有問題,為什麼多線程是個壞主意

在 Unix程式設計藝術 中,提到了盡量避免多線程程式設計模型, 認為這樣隻會增加複雜度, 提倡使用多程序, 這樣本質上就可以避免多線程『共享記憶體資料』産生的 “corruotped memory” 問題。

其中, 提到了一篇文章 Why Threads Are A Bad Idea, 對于多線程程式設計和事件程式設計分析的非常好, 具體的翻譯如下:

1 介紹

線程的背景:

在作業系統中出現多線程

逐漸演變成 使用者層面的程式設計工具

被認為是多種問題的一種通用解決方案

每一個程式員都需要成為 一個多線程程式設計的高手嗎?

根本性的問題:

多線程的程式非常難以正确的編寫!!!

替代性的方案:

使用事件驅動的程式設計方法

特别聲明:

對于大部分的多線程程式,使用事件驅動是一個更好的選擇

隻有當使用CPU多核的時候, 才需要使用多線程程式設計

2 多線程的本質

java多線程為什麼有問題,為什麼多線程是個壞主意

一般用來管理并發問題

多個獨立互相執行的任務

共享的記憶體

預先的安排機制(Pre-emptive scheduling)

同步機制(synchronization)

3 多線程的用途

作業系統: 對每一個使用者程序配置設定一個核心線程

科學應用程式: 每個CPU配置設定一個線程(對計算要求性很高的程式)

分布式系統: 程序請求并行(同步記性的I/O操作)

GUIs程式

線程對應使用者的行為. 在長時間的背景計算過程中仍然可以處理圖形展示

多媒體, 動畫方面的程式編寫

4 多線程有什麼問題?

java多線程為什麼有問題,為什麼多線程是個壞主意

對于一般的程式員而言,難以掌握。

即使對于專家,多線程程式設計也是痛苦的。

5 為什麼多線程程式設計很難?

Synchronization(同步機制):

必須通過鎖來共享資料

忘記了加鎖?就會導緻受污染的資料

死鎖

依賴鎖,會導緻循環依賴

每個處理程式等待其他處理程式: 導緻系統挂起

java多線程為什麼有問題,為什麼多線程是個壞主意

6 為什麼多線程程式設計很難?

難以調試: 因為 資料依賴,時間依賴

線程破壞了抽象: 無法設計出子產品化的程式

因為鎖導緻回調無法完成

java多線程為什麼有問題,為什麼多線程是個壞主意

7 為什麼多線程程式設計很難?

很難達到非常好的性能

簡單的鎖導緻了低并發

而精密的鎖又會導緻複雜度提升, 降低了一般情況下的性能

OSes限制了性能提升(排程, 環境切換)

線程不受支援

難以支援多線程代碼(mac, windows)

一些标志庫不是線程安全的

核心調用, windows系統不是多線程

很少有多線程程式設計的調試工具

通常不需要并發場景

8 時間驅動程式設計

一個執行流程序: 沒有CPU的并發

在時間上注冊消息(通過回調)

事件輪詢等待消息, 調用處理器模型

時間處理器沒有搶斷

處理器通常是 短生命周期的

java多線程為什麼有問題,為什麼多線程是個壞主意

9 事件驅動程式設計被用來幹什麼

大多數的GUIs程式設計:

一個處理器對應一個事件

處理器用來執行行為(撤銷,删除檔案等)

分布式系統

一個處理器用來對應一個輸入源

處理進來的請求,傳回結果

事件驅動的I/O 來處理 I/O并發

10 事件驅動程式設計的問題

長時間運作的時間處理器會導緻 程式沒有反應, 解決辦法:

對于長時間運作的程式Fork off子程式處理, 當處理結束後使用事件

打斷處理器執行(比如: 事件驅動的I/O)

定期回調 時間處理器中的 事件循環

通過處理器無法維護本地記憶體狀态(處理器必須傳回)

沒有CPU的并發(不太合适科學計算程式)

事件驅動的程式設計并不總是被支援

11 多線程程式設計 VS 事件驅動程式設計

事件驅動編發程式設計盡可能的避免 并發, 而多線程程式設計則傾向于并發:

使用事件驅動程式設計更加容易: 不用考慮并發, 不用考慮搶占, 不用考慮同步和死鎖

隻在特定的情況下,才使用複雜的技術棧

使用多線程程式設計, 即使最簡單的程式也需要面對很高的複雜度(full complexity)

使用事件驅動更加容易調試

事件驅動程式設計隻和時間依賴有關, 不需要考慮内部的排程

問題更加容易跟蹤: 較慢的按鈕點選反應 和 記憶體資料污染 時候, 前者問題更加容易定位

12 多線程程式設計 VS 事件驅動程式設計

在單個CPU上時間驅動程式比線程更加快速

沒有鎖的覆寫

沒有上下文環境的 切換

事件驅動程式設計更加面向接口程式設計

多線程提供了真正的并發性

對于多CPU的機器來說,是可以擴充性能

可以長時間的運作處理程式而不需要當機

13 你需要放棄多線程嗎?

不需要的情況: 對于應該程式性能要求很高的服務(比如: 資料庫伺服器)

但是, 盡可能的避免多線程程式設計:

對于 GUIs程式, 分布式系統, 性能要求不高的, 使用事件程式設計, 不是多線程

隻有當真正的多核CPU并發需要使用到的時候,使用多線程程式設計

當使用多線程程式設計的時候,将多線程程式設計子產品與其他子產品進行隔離, 保持大部分代碼都是單線程模型

隔離多線程的子產品:

java多線程為什麼有問題,為什麼多線程是個壞主意

14 總結

并發從根本上是很難的, 盡可能的避免

多線程比事件更加強大,但是這種強大的功能很少真正需要

多線程程式設計比事件程式設計更加難以寫出正确的代碼, 隻有真正的專家才能掌握

将事件 程式設計當做基本的開發工具(對于GUIs 和 分布式系統)

隻有當性能要求很高的服務時候,才使用 多線程