« | August 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | | | | | | |
| 公告 |
Welcome to iPUD's Sky! |
Blog信息 |
blog名称:阿布的天空 日志总数:29 评论数量:39 留言数量:-32 访问次数:165210 建立时间:2006年3月21日 |

| |
[JAVA学习]Singleton pattern, Double-checked Locking pattern 文章收藏, 网上资源, 软件技术
阿布 发表于 2006/4/2 14:42:09 |
koji
http://www.jsptw.com/jute/post/view?bid=25&id=3939&sty=1&tpg=2&age=0
double-checked locking範例n
1234567891011
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
if (instance == null) //2
instance = new Singleton(); //3
}
}
return instance;
}
表面上看來不會有問題 但是在實際上java環境下跑起來可能會如下的問題發生 這是因為現在的java環境下memory model的關係,允許out of order寫入(這邊中文不知這樣可不可以) 1.thread1 進入getInstance() 2.instance是null,所以thread1進入synchronized block 3.thread1執行到//3讓instance變成非null,但是此時並無執行constructor 4.thread1切換到thread2 5.thread2檢查instance是否是null,但是因為instance並非null,所以thread2只把雖已建構,但並無完全出始化的Singleton物件,參考到instance並取得. 6.thread2切換到thread1 7.thread1執行constructor並取得其參考,完成Singleton物件的初期化 另外一種,試圖解決out of order的做法
1234567891011121314151617
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
inst = new Singleton(); //4
}
instance = inst; //5
}
}
}
return instance;
}
主要為了避免之前的問題,導入了synchronized和使用inst變數的做法 理由如下 1.thread1 進入getInstance() 2.instance是null,所以thread1進入synchronized block 3.變數inst取得instance的值,//2但是為null 4.因為inst為NULL,所以thread1會在//3進入第二個synchronized block 5.接下來thread1於//4執行code,將inst改成非null,但是此時並無執行Singleton的constructor(也就是上面範例的缺陷發生原因) 6.thread1切換到thread2 7.thread2進入getInstance() 8.因為instance為null,因此thread2於//1會想進入synchronized block,但是現在被thread1所鎖住. 9.切換到thread1//4的部分被執行完畢 10.thread1將完整建構好的 Singleton 物件傳回給變數instance//5,結束兩個synchronized block 11.thread1回傳instance 12.接下來回到thread2,//2將instance代入到inst 13.thread2知道instance並非null,因此回傳instance 關鍵在於//5的部分,在寫上述範例中必須假設成,instance必須將會變成null或者是完全建構好的 Singleton 物件.當這個假設和事實衝突時,就是問題發生的原因了. 依照現行的memory model的定義,上面這個code將不會得到如我們預想的結果 ,JLS定義中無法將synchronized block內的code搬到外面,但是並沒有說明能將synchronized block外的搬到內部. jit compiler應該會抓住這部分,當作是最佳化的好機會,他會將//4和//5除去並結合,因此最佳化以後會變如下,同樣會造成out of order的問題.
123456789101112131415161718
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
//inst = new Singleton(); //4
instance = new Singleton();
}
//instance = inst; //5
}
}
}
return instance;
}
解決方式就像之前板上大家討論的 要碼就是
123456
public static synchronized Singleton getInstance()
{
if (instance == null) //1
instance = new Singleton(); //2
return instance; //3
}
不然就是
123456789101112131415161718
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
{
v = new Vector();
inUse = true;
//...
}
public static Singleton getInstance()
{
return instance;
}
}
底下那個String的測試code 在IBM 1.3 JVM和Sun 1.3 JVM沒有問題 但是在譬如舊的版本如1.2下 會產生問題 且會執行 System.out.println("String is not immutable!"); |
|
|