Java線程安全的單例模式

在Java併發編程實踐(JAVA concurrency in practice)中的第十六章(Java存儲模型)中.
有講到對象安全發佈.
其中就是以單例模式來說明這個安全初始化技巧的.這是學習分析總結如下:
[quote]
不正確發佈帶來的風險的真正原因是在"發佈共享對象"與從"另一個線程訪問它"之間,缺少happens-before排序.
[/quote]
不安全的發佈.
發佈(Publishing):
[quote]
發佈(Publishing)一個對象的意思是使它能夠被當前範圍之處的代碼所使用.比如將一個引用
存儲到其他代碼可以訪問的地方.在一個非千私有的方法中返回這個引用,也可以把它傳遞到其他類的方法中.在很多情況下,我們需要確保對象及它們的內部狀態不被暴露(publish).
[/quote]

代碼清單1:不安全的惰性初始化:

public class UnsafeLazyInitialization{
private static Resource resource;
public static Resource getInstance(){
if(resource == null){
resource = new Resource();
}
return resource;
}
}


[quote]
除了不可變對象以外,使用被另一個線程初始化的對象,是不安全的,除非對象的發佈是happens-before於對象的消費線程使用它.
[/quote]
安全初始化技巧:
代碼清單2 線程安全的惰性初始化

public class SafeLazyInitialization{
private static Resource resource;
public synchronized static Resource getInstance(){
if(Resource == null){
resource = new Resource();
}
}
}



代碼清單3 主動初始化

public class EagerInitialization{
private static Resource resource = new Resource();
public static Resource getResource() {
return resource;
}
}


像上面那樣,使用主動的初始化,避免了每次調用SafeLazyInitialization的getInstance()的同步開銷.這項技術可以和JVM的惰性類加載相結合,
創建一種惰性初始化技術,使得在通常的代碼路徑中都不需要同步.清單4的惰性初始化holder類技巧.使用一個專門用來初始化Resource的類.JVM將ResourceHolder的初始化被 延遲到真正使用它的時刻.因爲Resource是在靜態初始進行初始化的,所以不再需要額外的同步.,線程第一次調用getResource,引起ResourceHolder的加載和初始化,這個時候,正是靜態初始階段Resource完成初始化發生的時間.

清單4惰性初始化Holder類技巧

public class ResourceFactory{
private static ResourceHolder {
public static Resource resource = new Resource();
}
public static Resource getResource(){
return ResourceHolder.resource;
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章