我們常說,如果將物件放入到執行緒安全容器,例如vector或synchronizedmap時,那麼物件就可以安全地發布,後續的每個執行緒都可以安全地訪問。
按照我們上一節的論述,這裡的安全包含物件的內蘊狀態嗎,還是依舊僅僅只有物件的引用?
經過測試,我們可以發現,所有的執行緒安全容器依舊只能保證物件的引用更改是安全的,也就是說,只有當物件的引用位址發生了變化,其他執行緒才能感知到這種變化。
示例**如下,依舊以計數為例:
// 類本身不是執行緒安全的,絕不會因為放入執行緒安全容器,就會變成執行緒安全的類了
static class person
public
long
getage()
}
測試**如下:
final string key = "key";
final person person = new person();
// 放入執行緒安全容器
final mapvalues = collections.synchronizedmap(maps.newhashmap(key, person));
// 四個執行緒同時計數
for (int i = 0; i < 4; i++)
}}.start();
}
從結果來看,最後「person.getage()」依舊不能達到100的計數,所以物件的內容依舊不是執行緒安全的。
下面說簡單的解決辦法,因為物件的獲取是執行緒安全的,但遞增的方法(yiifaa.increment())是不安全的,所以只需要最小的鎖同步,如下:
person yiifaa = values.get(key);
// 當然觀察鎖也不一定要是yiifaa,只要是共享物件都可以,如key
synchronized(yiifaa)
count--;
從上面的**可以看出,鎖與共享變數並沒有直接的關係,只需要保證所有的執行緒在同乙個鎖上同步即可。
在使用synchronizedmap、synchronizedlist、concurrentmap時要千萬注意,執行緒安全容器僅僅只能保證物件的引用可見性,而不能內容的可見性。
併發程式設計(七) 安全發布物件
發布物件是指使乙個物件能夠被當前範圍之外的 所使用 物件逸出是一種錯誤的發布,指當乙個物件還沒有構造完成時,就使它被其他執行緒所見 slf4j public class escape private class innerclass escape.this thiscanbeescape publi...
併發學習(十) 安全物件發布
平時我們建立的物件往往不會考慮到安全物件的概念,這可能比較陌生,但是你面試的時候面試官很喜歡問你執行緒安全的單例模式,而這就是相關的知識點 發布 使物件能夠在除了當前作用域之外的地方使用 最常用的方法 將物件的引用儲存到乙個公有的靜態變數中,讓任何類和執行緒都能看到該物件。逸出 某個物件不應該被發布...
(二)Java併發學習筆記 安全發布物件
上邊關於逸出的概念講述的很是模糊,下面列舉幾個逸出的示例。通過靜態變數引用逸出 public static setknownsecrets public void initialize 上邊 示例中,呼叫initialize方法,發布了knowsecrets物件。當你向knowsecrets中新增乙...