1. 程式人生 > >《Java併發程式設計實踐——第一章(介紹)、第二章(執行緒安全)》

《Java併發程式設計實踐——第一章(介紹)、第二章(執行緒安全)》

介紹##

1.1 併發的簡短歷史

相同的關注點(資源利用,公平和方便) 不僅促進了程序的發展,也促進了執行緒的發展、
執行緒允許程式控制流的多重分支同時存在於一個程序。它們共享程序範圍內的資源,比如記憶體和檔案控制代碼,但是執行緒有自己的程式計數器、棧、和本地變數。

1.2 執行緒的優點

提高效能,降低程式複雜度。在伺服器應用中,提高資源利用率和吞吐量。

1.3 執行緒的風險

1.3.1 安全危險

在這裡插入圖片描述
競爭條件:當被多執行緒呼叫時,getNext是否能返回不重複的值。
因為執行緒共享相同的記憶體地址空間,且併發地執行,它可能訪問或修改其他執行緒正在使用的變數。

1.3 執行緒無處不在

定時器:Timer訪問的資料必須是執行緒安全的。
Servlet:Servlet可能會訪問共享的物件(Session等),必須是執行緒安全
遠端方法呼叫:RMI使你能夠呼叫在另外一個JVM上執行的物件的方法。

執行緒安全##

編寫執行緒安全的程式碼,本質上就是對狀態的方法,而且通常都是共享的、可變的狀態。

狀態:一個物件的狀態就是它的資料,儲存在狀態變數,比如例項或靜態域。
包含了任何會對它外部可見行為產生影響的資料。
共享:指一個變數可以被多個執行緒訪問。
可變:指變數在其生命週期內可以改變。

2.1 什麼是執行緒安全性

在這裡插入圖片描述

2.1.1 無狀態的servlet

無狀態物件永遠是執行緒安全的。

不包含域,也沒有引用其他類的域

2.2 原子性

原子性:不能作為單獨的、不可分割的操作。
count++:包含了三次操作,讀-改-寫。

2.2.1 競爭條件

檢查再執行:使用潛在的過期觀察值來做決策或執行計算。

2.2.2 惰性初始化中的競爭條件

檢查再執行的常見用法是惰性初始化:
在這裡插入圖片描述
競爭條件並不總是失敗的,還需要某些特殊的分時。

2.2.3 複合操作

檢查再執行和讀-改-寫的操作看成複合操作:操作必須原子地執行。
可以使用已有的執行緒安全類:aromic包。

2.3 鎖

為了保護狀態的一致性,要在單一的原子操作中更新相互關聯的狀態變數。

2.3.1 內部鎖

內部鎖:每個Java物件都可以隱式地扮演一個用於同步的鎖的角色。
在這裡插入圖片描述

synchronized放的鎖就是該方法所在的物件本身。

2.3.2 重進入

當一個執行緒請求其他執行緒已經佔有的鎖時,請求執行緒將被阻塞。
然後內部鎖是可重進入的。
JVM會被每個鎖關聯一個請求計數,計數為0表示未被佔有。
在這裡插入圖片描述
子類覆寫了父類的synchronized型別的方法,如果沒有可重入鎖,看上去像死鎖。

2.4 用鎖來保護狀態

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

2.5 活躍度和效能

在這裡插入圖片描述

service方法宣告為synchronized,因此每次只能有一個執行緒執行它。這違背了Servlet的初衷:同時處理多個請求。
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述