天天看點

《Java線程與并發程式設計實踐》—— 2.4 volatile和final變量

本節書摘來異步社群《java線程與并發程式設計實踐》一書中的第2章,第2.4節,作者: 【美】jeff friesen,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

你之前學到的同步展示了兩種屬性:互斥性和可見性。synchronized關鍵字與兩者都有關系。java同時也提供了一種更弱的、僅僅包含可見性的同步形式,并且隻以volatile關鍵字關聯。

假設你自己設計了一個停止線程的機制(因為無法使用thread不安全的stop()方法))。清單2-2中threadstopping程式源碼展示了該如何完成這項任務。

清單2-2 嘗試停止一個線程

javac threadstopping.java

運作程式:

java threadstopping<code>`</code>

你應該能觀測到一系列運作時的消息。

當你在單處理器/單核的機器上運作這個程式的時候,很可能會觀測到程式停止。但是在一個多處理器的機器或多核單處理器的機器上,可能就看不到程式停止,因為每個處理器或者核心很可能有自己的一份stopped的拷貝,當一條線程修改了自己的拷貝,其他線程的拷貝并沒有被改變。

你或許決定使用synchronized關鍵字以確定隻能通路主存中的stopped變量。然後經過一番思考,你決定在清單2-3中使用同步通路一對臨界區的方式來解決這個問題。

清單2-3 嘗試使用synchronized來停止一個線程

public void run()

{

boolean _stopped = false;

while (!_stopped)

}

}<code>`</code>

不過,每次循環疊代都要嘗試擷取鎖的方式會存在性能開銷(還不如以前),是以這個解決方式是得不償失的。清單2-4展示了一個更為高效且整潔的方法。

清單2-4 嘗試通過volatile關鍵字來停止一個線程

import java.util.set;

import java.util.treeset;

public final class planets

private final set planets = new treeset&lt;&gt;();

public planets()

public boolean isplanet(string planetname)

清單2-5展示了一個不可變類planets,其對象存儲着星球名字的集合。盡管集合是可變的,但這個類的設計卻保證在構造函數退出之後,集合不會再被改變。通過聲明planet``s為final,這個屬性的引用不能被更改。而且,該引用也不能被緩存,是以緩存變量的問題也不複存在。

關于不可變對象,java提供了一種特殊的線程安全的保證。即便沒有用同步來釋出(暴露)這些對象的引用,它們依然可以被多條線程安全地通路。不可變對象提供了下列易于識别的規則:

不可變對象絕對不允許狀态變更。

所有的屬性必須聲明成final。

對象必須被恰當地構造出來以防this引用脫離構造函數。

最後一點很讓人迷惑,是以這裡給出一個this顯式地脫離構造函數的簡單例子: