執行緒安全性
要編寫安全執行緒的代碼其核心在於要對狀態訪問進行管理,特別是對共用的和可變的狀態的訪問。
非正式的說,對象的狀態是指儲存在狀態變數中的資料。對象的狀態也可能還包括其他對象的域。
“共用”變數可以由多個線程同時訪問,而“可變”意味著變數的在其生命週期內可以發生改變。
一個對象是否需要多線程,取決去它是否被多個線程訪問。
如果保證多線程訪問同一個可變的狀態變數時,不會出現錯誤。有三種方式可以解決該問題:
不線上程之間共用該可變狀態。 將狀態變數修改為不可變的變數。 在訪問狀態變數時使用同步。 編寫並發應用程式一種正確的編程方法是:首先使代碼正確運行,然後在提高代碼速度。效能的最佳化最好也只是當效能測試結果和應用程式必須提高效能,以及測試結果表明這種最佳化確實能偶帶來效能的提升時,才進行最佳化。 正確性的含義是,某個類的行為與其規範完全一致。 執行緒安全性定義:當多個線程訪問某個類時,這個類始終都能變現出正確的行為,那麼這個類就是安全執行緒的。 無狀態類:即類中不包含任何域,也不包含任何對其他類中域的引用。 無狀態對象一定是安全執行緒的。 在並發編程中,這種由於不恰當的執行時序出現不正確的結果是一種非常重要的情況,這叫:競態條件。競態條件發生的原因是:當某個計算正確性取決於多個線程的交替執行時序時,那麼就會發生競態條件。 競態條件的類型有: “先檢查後執行”操作。 “讀取——修改——寫入”操作。 如何避免競態條件問題的發生:必須在某個線程修改該變數時,通過某種方式防止其他線程修改這個變數,從而確保其他線程只能在修改操作完成之前或之後讀取和修改狀態,而不是在修改狀態的過程中。 在實際情況中,儘可能地使用現有安全執行緒對象來管理類的狀態。 要保持狀態的一直性,就需要在某個原子操作中更新所有相關的狀態變數。 內建鎖是可重新進入的,因此如果某個線程試圖獲得一個已經由它自己持有的鎖,那麼這個請求就會成功。“重入”意味著擷取鎖的操作粒度是“線程”,而不是“調用”。 對同步變數的訪問在任何位置都需要使用同步,而且還必須是同一個鎖。
對象的共用 在訪問共用的可變狀態是需要正確的管理。 為了確保多個線程之間對記憶體寫入操作的可見度,必須使用同步機制。 只要有資料在多個線程之間共用,就使用正確的同步。 加鎖是為了保證變數的可見度和原子性。 在使用volatile變數,若且唯若滿足一下所有條件: 對變數的寫入操作不依賴變數的當前值,或者能夠確保只有單個線程修改變數的值。 該變數不會與其他變數一起納入不變性條件中。 在訪問該變數時不需要加鎖。 發布是指:對象能夠在當前範圍之外的代碼中使用。發布內部狀態可能會破壞封裝性,並使得程式難以維持不變性條件。 當某個不應該發布的對象被發布時,這種情況就被稱為 逸出。 不要在構造過程中使this引用逸出。