併發編程的理論基石

1、進程和線程

1.操做系統、進程、線程的關係

操做系統是包含多個進程的容器,而每一個進程又是容納多個線程的容器。html

2.Oracle 官方定義

官方定義編程

  • 進程:使用 fork(2) 系統調用建立的UNIX 環境(例如文件描述符,用戶 ID 等),它被設置爲運行程序。
  • 線程:在進程上下文執行的一系列指令。

3.什麼是進程

  • 進程(Process)是程序的運行實例。
  • 進程是程序向操做系統申請資源(如內存空間和文件句柄)的基本單位。

在用戶下達運行程序的命令後,就會產生進程,任務管理器中的每個應用都是一個進程。谷歌瀏覽器的每一個標籤頁和插件都是一個進程。瀏覽器

4.什麼是線程

線程是操做系統可以進行資源調度的最小單位,它被包含在進程之中,是進程中的實際運做單位,每一個線程執行的都是進程代碼的某個片斷,特定的線程老是在執行特定的任務。tomcat

5.進程和線程的關係

5.1 起源不一樣

先有進程,後有線程。進程因爲資源利用率、公平性和便利性誕生。處理器的速度每每比外設的速度快(鍵盤、鼠標等),爲了提升 CPU 的利用率,誕生了線程,目的就是爲了提升程序的執行效率。安全

5.2 概念不一樣

  • 進程是資源分配的最小單位。
  • 線程是程序執行的最小單位(線程是操做系統可以進行資源調度的最小單位,同個進程中的線程也能夠被同時調度到多個 CPU 上運行),線程也被稱爲輕量級進程。

5.3 內存共享方式不一樣

  • 默認狀況下,進程的內存沒法與其餘進程共享(進程間通訊經過 IPC 進行)。
  • 線程共享由操做系統分配給其父進程的內存塊。

5.4 擁有資源不一樣

  • 操做系統爲各個獨立執行的進程分配各類資源,包括內存,文件句柄以及安全證書等。
  • 線程會共享進程範圍內的資源,例如內存句柄、文件句柄、進程用戶 ID 以及進程組 ID 等。每一個線程也有各自獨立的資源,例如線程 ID、程序計數器、棧以及局部變量等。

5.5 數量不一樣

一個程序至少擁有一個進程,一個進程至少擁有一個線程。服務器

5.6 開銷不一樣

  • 線程的建立、終止時間比進程短。
  • 同一進程內的線程切換時間比進程短。
  • 同一進程的各個線程間共享內存和文件資源,能夠不經過內核進行通訊。

5.7 生命週期相似

進程和線程都包含就緒、運行、等待狀態。網絡

6.Java 和多線程的關係

Java 在設計之初就支持了多線程,並且 Java 中的線程會一對一映射到操做系統的內核線程中(實際的線程數量,不是虛擬線程)。除了咱們啓動的線程,還包括 JVM 自啓動線程。多線程

2、多線程

1.什麼是多線程

1.1 概念

多線程是指單個進程中運行多個線程,若是一個程序容許運行兩個或以上的線程,那麼它就是多線程程序。併發

1.2 例子

  • 房間的例子oracle

    • 客廳:公共空間
    • 廁所:鎖
    • 獨立房間:線程共享空間
    • 打掃衛生:線程合做
  • 火鍋的例子

    • 大火鍋一我的吃:單進程單線程
    • 大火鍋多我的吃:單進程多線程

2. 使用多線程的緣由

2.1 發揮多核處理器的強大能力

  • 充分發揮多核 CPU 的優點,提升處理器速度。
  • 避免無效等待(進行 I/O 操做時能夠處理其餘事情)。
  • 提高用戶體驗性,避免卡頓,縮短等待時間

    • 並行處理,提升性能,一般用於服務器(例如 Tomcat),用多個線程去處理接收的 HTTP 請求。
    • 在 Android 開發中,主線程的任務之一就是繪製屏幕, 主線程不容許進行IO 操做或網絡請求,目的就是爲了不卡頓,影響用戶的體驗。

2.2 便於編程建模

將大的任務分割爲多個小任務,分別創建程序模型,並經過多線程分別運行這幾個任務。

2.3 計算機的性能定律

  • 摩爾定律失效

摩爾定律——當價格不變時,集成電路上可容納的元器件的數目每一個 18-24 個月就會翻一倍以上,性能也會提高一倍。

  • 阿姆達爾定律(Amdahl)登臺

阿姆達爾定律:處理器越多,程序執行就越快,但有上限,取決於程序中串行部分的比例,並行的比例越高,多處理器的效果越明顯。

最下面藍色曲線,當並行的比例爲 50% 時,最快速度能夠提高2倍;最上面綠色曲線,當並行的比例爲 95% 時,最快速度能夠提高20倍。

3.多線程使用場景

  • 後臺線程,如執行定時任務。
  • tomcat——每次有一個新的請求過來的時候,tomcat 會把這個請求交給一個新的線程去處理。
  • 多線程後臺並行下載文件。

4.多線程的風險

4.1 安全性問題

當多個線程同時訪問和修改相同的變量時,將會在串行編程模型中引入非串行因素,如 i++ 的數據錯誤。

4.2 活躍性問題

當某個操做沒法繼續執行下去的時候,就會發生活躍性問題,如死鎖、飢餓以及活鎖。

4.3 性能問題

在多線程程序中,當線程調度器臨時掛起活躍線程並轉而運行另外一個線程時,就會頻繁得出現上下文切換操做(Context Switch),這種操做會帶來極大的開銷:保存和恢復執行上下文,丟失局部性,而且 CPU 將更多的時間花在線程調度而不是線程運行上。當線程共享數據時,必須使用同步機制,而這些機制每每會抑制某些編譯器優化,使內存緩衝區的數據無效,以及增長共享內存總線的同步流量。這些因素都將帶來額外的性能開銷。

3、串行、並行、併發

1.串行

串行是將多個任務按順序排隊執行,例如:聽完音樂再寫代碼。

2.並行

真正的「同時」運行,在同一時刻有多個任務執行,須要多核處理器,由於單核處理器沒法在同一時刻執行多個任務。例如:邊聽音樂邊寫代碼。

3.併發

  • 兩個或多個任務能夠在重疊時間段內啓動,運行和完成。
  • 並行(兩個線程同時執行)必定是併發,併發並不必定是並行。
  • 例如一下子聽音樂,一下子寫代碼,輪流執行。

4.高併發

4.1 概念

同時有不少個請求發送給服務器系統,服務器並行處理請求。

4.2 多線程和高併發

高併發是一種狀態,多線程是高併發的一種重要解決方案,高併發並不意味着多線程。

4.3 高併發指標

  • QPS(Queries Per Second)
  • 帶寬
  • PV (Page View)
  • UV(Unique Visitor)
  • 吞吐率(Requests Per Second)
  • 併發鏈接數(The number of concurrent connections)
  • 服務器平均請求等待時間(Time per request: across all concurrent requests)

5、同步、異步、阻塞、非阻塞

1.同步與異步

  • 同步和異步關注的是消息通訊機制,這裏指的是被調用者(也就是服務器的行爲)而不是請求方的行爲。
  • 同步(Synchronous):客戶端發出一個請求後,一直等到服務端返回最終的結果。
  • 異步(Asynchronous):客戶端發出一個請求後,還能夠發出另外的請求,不用等待以前請求的結果返回。

2.阻塞與非阻塞

  • 阻塞非阻塞是針對調用者的,在結果返回前,是否還能作別的事情。阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.。
  • 阻塞:客戶端發起一個請求後,當前線程會被掛起,直到服務端返回結果。
  • 非阻塞:客戶端發起一個請求後,無論服務器會不會馬上返回結果,當前線程都不會被掛起。

3.例子

水壺燒水的例子,有兩種水壺,一種普通水壺,只能本身觀察水是否燒開;一種帶提醒的水壺,水燒開會有聲音提醒。

  • 同步阻塞:用普通水壺燒水,一直等着該水壺的水燒開。
  • 同步非阻塞:用普通水壺燒水,而後去客廳看電視,時不時觀察水燒開了沒。
  • 異步阻塞:用帶提醒的水壺燒水,一直等着該水壺的水燒開。
  • 異步非阻塞:用帶提醒的水壺燒水,而後去玩手機,直到該水壺發出聲音提醒。
《Java併發編程實戰》

怎樣理解阻塞非阻塞與同步異步的區別?

燦爛一輩子

相關文章
相關標籤/搜索