JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Software Design » GoF  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
本主題所含的標籤
無標籤
作者 [DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [精華]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2003-07-19 16:13 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
顧名思義, 就是系統中該 class 只建立一個 object: Class.

主要是利用 class 中 constructor 的 accessblity. e.g.
1
2
3
4
5
6
7
8
9
10
class CLASS {
    static private CLASS obj = null;
    private CLASS() {}
 
    static public CLASS getInstance() {
        if (obj == null)
            obj = new CLASS();
        return obj;
    }
}


1
2
3
4
class CLASS {
    static public final CLASS obj = new CLASS();
    private CLASS() {}
}


把 constructor 設為 private 讓其他 client 無法直接建立物件. client 如果要取得這單一物件則必須經由 static public method 來取的物件.

當然你也可以把數量設定為你需要的數量, 不一定只有一個. 只不過還叫 singleton 可能就不太適合了. 但如果你想要把物件定為某些 class 可以用, 那就應該問一下 popcorny 答案了....

UML: 不清楚對不對, 大家作參考吧...


popcorny edited on 2003-07-20 11:57
reply to postreply to post
作者 Re:[DP]Singleton, Double-check Locking(by Biologic [Re:popcorny]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2003-07-19 16:17 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Biologic wrote:
1
2
3
4
5
6
7
8
class CLASS {
static private CLASS obj=null;
  private CLASS(){}
  static public CLASS getInstance() {
    if (obj==null) obj=new CLASS();
    return obj;
  }
}



恩...這是一個常用的寫法
singleton + lazy initialization
但是這會有小小小小的問題..
就是剛好很衰的同時有兩個thread在呼叫getInstance的method...
而且衰到情況如下
Thread1: if(obj == null) //true
Thread2: if(obj == null) //true
Thread1: obj = new CLASS(); //產生一個instance並assign給obj
Thread2: ojb = new CLASS(); //又產生一個instance並assign給obj
如此就產生兩個instance...
也就是違背了singleton的精神

因此會有如此的改良
1
2
3
4
5
6
7
8
9
public class CLASS {
    static private CLASS obj=null;
    private CLASS(){}
    synchronized static public CLASS getInstance() {
        if (obj==null) 
            obj=new CLASS();
        return obj;
    }
}

也就是加上synchronized這個keyword來保證同時只有一個thread呼叫此method

但.....
這還不是最好的解法
因為可能getInstance常常呼叫..
如果程式中很多thread在跑...
這邊可能就會變成一個效能殺手(如果你斤斤計較的話)
所以又有一個pattern叫double-check locking的pattern
code如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CLASS {
    static private CLASS obj=null;
    private CLASS(){}
    static public CLASS getInstance() {
        if (obj==null){
            synchronized(CLASS.class){
                if(obj == null){
                     obj=new CLASS();
                }
            }
        }
        return obj;
    }
}

這樣就兼顧效率...
又可以做到lazy initialization

可是程式很醜對不對
如果每次singleton都這樣寫
大概會發瘋吧
所以有一種反璞歸真的寫法
1
2
3
4
5
6
7
public class CLASS {
    static private CLASS obj= new CLASS();
    private CLASS(){}
    static public CLASS getInstance() {
        return obj;
    }
}

什麼問題都解決啦
不過缺點就是沒有lazy initialization
不過如果你的class initialization不會很久
事實上最後一個寫法就綽綽有餘了


popcorny edited on 2003-07-19 16:21
reply to postreply to post
作者 Re:[DP]Singleton, Double-check Locking(by Biologic [Re:popcorny]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-19 16:33 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
因為沒有人提出關於 UML 的對錯問題, 所以我只好自己回了.

轉貼: http://www.bearguru.com/projects/XPDPTL/GOF/html/Singleton.html


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-check Locking pattern (by Biologic) [Re:popcorny]
ymshin





發文: 277
積分: 4
於 2003-07-20 04:01 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
About DCL:

" Double-checked locking: Clever, but broken "
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double_p.html

"Can double-checked locking be fixed? "
http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html

"Can ThreadLocal solve the double-checked locking problem?"
http://www.javaworld.com/javaworld/jw-11-2001/jw-1116-dcl.html

看到的文章中同時對 DCL & Singleton 說明最詳盡的網頁:

http://www-6.ibm.com/jp/developerworks/java/020726/j_j-dcl.html

Lazy initiation in Java:

http://www.javaworld.com/javaworld/javatips/jw-javatip67-p2.html

enjoy~~~


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-check Locking pattern (by Biologic) [Re:ymshin]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-20 09:47 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
ymshin wrote:
About DCL:

" Double-checked locking: Clever, but broken "
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double_p.html

"Can double-checked locking be fixed? "
http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html

"Can ThreadLocal solve the double-checked locking problem?"
http://www.javaworld.com/javaworld/jw-11-2001/jw-1116-dcl.html

看到的文章中同時對 DCL & Singleton 說明最詳盡的網頁:

http://www-6.ibm.com/jp/developerworks/java/020726/j_j-dcl.html

Lazy initiation in Java:

http://www.javaworld.com/javaworld/javatips/jw-javatip67-p2.html

enjoy~~~


抱歉, 我是覺得 popcorny 已經解釋的很清楚了... 應該不需要任何其他文件了吧...?

裡面的程式碼:
1.
synchronized {
if (resource == null)
resource = new Resource();
}
synchronized block 要加 object. 我測試時不能用... (illegal start of expression)

2.
public static Resource resource = new Resource();
resource 可以設為 null.... 這樣還是有可能會出問題... 可能需要考慮再加個 final. 想想... Java 就是有個好處, 永遠不怕被 delete.


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-check Locking pattern (by Biologic) [Re:Biologic]
ymshin





發文: 277
積分: 4
於 2003-07-20 10:47 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Biologic wrote:
抱歉, 我是覺得 popcorny 已經解釋的很清楚了... 應該不需要任何其他文件了吧...?

裡面的程式碼:
1.
synchronized {
if (resource == null)
resource = new Resource();
}
synchronized block 要加 object. 我測試時不能用... (illegal start of expression)

2.
public static Resource resource = new Resource();
resource 可以設為 null.... 這樣還是有可能會出問題... 可能需要考慮再加個 final. 想想... Java 就是有個好處, 永遠不怕被 delete.


您可能沒有看文章內容...因為 popcorny 大大寫的不是 DCL broken 的主因, 所
以把先前貼的文章轉貼過來再加幾篇補述...前三篇是在 JVM 1.3 以前的環境,
自然有差...jp ibm 那篇說明詳盡, 最後那篇是為什麼當初會有 DCL 產生, 以及
java 環境下是否需要那種作法...


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-check Locking pattern (by Biologic) [Re:ymshin]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-20 12:47 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
ymshin wrote:
您可能沒有看文章內容...因為 popcorny 大大寫的不是 DCL broken 的主因, 所
以把先前貼的文章轉貼過來再加幾篇補述...前三篇是在 JVM 1.3 以前的環境,
自然有差...jp ibm 那篇說明詳盡, 最後那篇是為什麼當初會有 DCL 產生, 以及
java 環境下是否需要那種作法...


你何不解釋一下呢?? 並非所有人懂英文, 更何況是日文呢?
JP ibm 我是真的沒有看, 因為我實在看不懂日文...


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:popcorny]
koji

秒速5センチメートル

站長

發文: 8415
積分: 19
於 2003-07-20 13:49 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
我幫忙翻譯一下好了Tongue

前面幾個範例很簡單所以不說明
直接跳到日文jp的第四個項目

double-checked locking範例n
1
2
3
4
5
6
7
8
9
10
11
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的做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的問題.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}


解決方式就像之前板上大家討論的
要碼就是
1
2
3
4
5
6
public static synchronized Singleton getInstance()
{
  if (instance == null)          //1
    instance = new Singleton();  //2
  return instance;               //3
}


不然就是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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!");


koji edited on 2003-07-20 14:06
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-check Locking pattern (by Biologic) [Re:Biologic]
ymshin





發文: 277
積分: 4
於 2003-07-20 13:58 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Biologic wrote:
你何不解釋一下呢?? 並非所有人懂英文, 更何況是日文呢?
JP ibm 我是真的沒有看, 因為我實在看不懂日文...


這...我貼連結前好像都有註明文章性質吧?

此外, 那個日文版算是 summary, javaworld 的文章對於詳細運作方式說的比較
詳盡, 也非常感謝 koji 的幫忙, 造福人群. Smile

Java 中不需要額外寫 lazy initialization method 解決初始化的問題, 板主大人的
反璞歸真 code 就是正解了, 而且也是 lazy initialization, 原因曾經提過, 先前貼
的最後一篇文章也說的很清楚, 就不再重複留言. Shy


ymshin edited on 2003-07-20 14:06
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:koji]
koji

秒速5センチメートル

站長

發文: 8415
積分: 19
於 2003-07-20 14:03 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
另外那篇文章的作者將
instance =new Singleton();
改成如下的疑似程式碼
1
2
3
4
5
mem = allocate();             //Allocate memory for Singleton object.
instance = mem;               //Note that instance is now non-null, but
                              //has not been initialized.
ctorSingleton(instance);      //Invoke constructor for Singleton passing
                              //instance.

此疑似碼並不是可能產生的狀況,而是在許多JIT compiler中實際運作的例子.運作的順序不太對,但是依照現行的memory model,這是可行的.而在JIT compiler下會執行如上的動作,表示我們不能再忽視double-checked locking的問題.

底下的程式碼將用來解釋此問題
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Singleton
{
  private static Singleton instance;
  private boolean inUse;
  private int val;  
 
  private Singleton()
  {
    inUse = true;
    val = 5;
  }
  public static Singleton getInstance()
  {
    if (instance == null)
      instance = new Singleton();
    return instance;
  }
}


在Sun JDK 1.2.1 JIT compiler下所產生的assembly code如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;asm code generated for getInstance
054D20B0   mov         eax,[049388C8]      ;load instance ref
054D20B5   test        eax,eax             ;test for null
054D20B7   jne         054D20D7
054D20B9   mov         eax,14C0988h
054D20BE   call        503EF8F0            ;allocate memory
054D20C3   mov         [049388C8],eax      ;store pointer in 
                                           ;instance ref. instance  
                                           ;non-null and ctor
                                           ;has not run
054D20C8   mov         ecx,dword ptr [eax] 
054D20CA   mov         dword ptr [ecx],1   ;inline ctor - inUse=true;
054D20D0   mov         dword ptr [ecx+4],5 ;inline ctor - val=5;
054D20D7   mov         ebx,dword ptr ds:[49388C8h]
054D20DD   jmp         054D20B0


可以看到在054D20C3部分將會讓instance變成非null,但是並沒有執行constructor,因此在此狀態下會產生double-checked locking的破綻.

所以在C3到完成建構之間有其他動作從中切入,double-checked locking將會失敗

看了以後在翻,翻的有點爛,請多指教Q_Q

謝謝版友的連結又讓我學的更詳細很多呵呵


koji edited on 2003-07-20 14:09
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:koji]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-20 14:09 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
koji wrote:
我幫忙翻譯一下好了Tongue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的問題.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}



原來如此...
問題1. 第二個 synchronized 是做什麼用的?? 我想不到任何用途...
問題2. 最佳化的防止法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void setInstance(Singleton si) {
  instance=si;
}
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        
        }
        setInstance(inst);               //5
      }
    }
  }
  return instance;
}

不知道有沒有效...?? 我總覺得 //3 是多餘的...


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:koji]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2003-07-20 15:09 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
太感謝koji兄的翻譯了
我這個板住在耍廢...
還好我說過了..只是整理文章的小弟

不過好像還是沒有人清楚的提到DCL是哪裡會出現問題
日文的那篇好像沒有提到吧??
ymshin題供的前三篇有提到
不過我有看沒有懂
只說是Java Memory Model造成的??
那 ....怎麼造成的??
JDK1.4解決了嘛??
為什麼我們看似萬無一失的程式卻還是有可能有錯誤呢??
有沒有讓java失去write one run everywhere的特性..??
這是我比較好奇的...還請各為板友幫忙解答


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:popcorny]
ymshin





發文: 277
積分: 4
於 2003-07-20 15:41 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
popcorny wrote:
太感謝koji兄的翻譯了
我這個板住在耍廢...
還好我說過了..只是整理文章的小弟

不過好像還是沒有人清楚的提到DCL是哪裡會出現問題
日文的那篇好像沒有提到吧??
ymshin題供的前三篇有提到
不過我有看沒有懂
只說是Java Memory Model造成的??
那 ....怎麼造成的??
JDK1.4解決了嘛??
為什麼我們看似萬無一失的程式卻還是有可能有錯誤呢??
有沒有讓java失去write one run everywhere的特性..??
這是我比較好奇的...還請各為板友幫忙解答


我灌一下水好了, 順便湊一下作業的篇數~Big Smile

簡單說也就是 DCL 的設計基礎有問題; 它是假設所有 threads 處理是經由循序
方式一個個排隊等著執行, 可是實際上的處理為了執行效能並不是如此動作;
threads 間雖然用 synchronized 包起來, 那也只是防止進出的讀寫, 並不能防止
被偷窺, 部分執行中的產生值可能被抓取, 所以在 thread 離開 main memory
換下一個 thread 進去執行時會發生不可預料的結果, DCL 也就是個失敗的設
計,廢棄的 pattern.

DCL 是為了因應 lazy initialiaztion 所產生的 pattern, 主要是因為 C++ 等其它
語言的編譯機制必須由 developer 解決這個問題, java 的運作機制不同, 使用
private static field 就可以達成晚 create instance 的功能, 所以無須利用到
DCL 這樣的寫法. C++ 一段時間沒碰, 而且連 STL 都不是很熟, 所以不清楚這
種 threads 問題現在是如何解決的, JVM1.4 的運作方式鐵定改很多, 光從效能
就可知道演算法和 1.3 版差異一定很大; 既然 Java 環境中不需要作冒險動作,
板主大人的最後一個示範 code 就很好用了. Big Smile

如果有說錯的地方還請指正. 我原本也沒看這麼細哪~~~謝謝 popcorny 提出
這麼好的問題讓我跟著學習~Shy

差點忘了, DCL 跟 JVM threads 的處理方式有關, 所以不會造成 bytecode 換
平台不能用, "頂多"是執行結果無法預料而已. Big Smile


ymshin edited on 2003-07-20 16:02
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:ymshin]
browser

戀香

版主

發文: 3570
積分: 1
於 2003-07-20 16:01 user profilesend a private message to usersend email to browserreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
ymshin wrote:
我灌一下水好了, 順便湊一下作業的篇數~Big Smile

簡單說也就是 DCL 的設計基礎有問題; 它是假設所有 threads 處理是經由循序
方式, 可是實際上的處理為了執行效能並不是如此動作; threads 間雖然用
synchronized 包起來, 那也只是防止讀寫, 並不能防止被偷窺, 部分執行中的產
生值可能被抓取, 所以在 thread 離開 main memory 換下一個 thread 進去執
行時會發生不可預料的結果, DCL 也就是個失敗的設計,廢棄的 pattern.

DCL 是為了因應 lazy initialiaztion 所產生的 pattern, 主要是因為 C++ 等其它
語言的編譯機制必須由 developer 解決這個問題, java 的運作機制不同, 使用
private static field 就可以達成晚 create instance 的功能, 所以無須利用到
DCL 這樣的寫法. C++ 一段時間沒碰, 而且連 STL 都不是很熟, 所以不清楚這
種 threads 問題現在是如何解決的, JVM1.4 的運作方式鐵定改很多, 光從效能
就可知道演算法和 1.3 版差異一定很大; 既然 Java 環境中不需要作冒險動作,
板主大人的最後一個示範 code 就很好用了. Big Smile

如果有說錯的地方還請指正. 我原本也沒看這麼細哪~~~謝謝 popcorny 提出
這麼好的問題讓我跟著學習~Shy


並不能防止被偷窺
這裡的 偷窺 是指 .. 取得 的意思嗎 ?
還是說 .. 這個是由原文的專有名詞 .. 直接譯過來的 ....


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:browser]
ymshin





發文: 277
積分: 4
於 2003-07-20 16:04 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
browser wrote:
並不能防止被偷窺
這裡的 偷窺 是指 .. 取得 的意思嗎 ?
還是說 .. 這個是由原文的專有名詞 .. 直接譯過來的 ....


就是取得的意思~~~自然不是專有名詞...又被抓到一次中文濫用的包~~~
EmbaressedEmbaressedEmbaressed

我要去傳統文學網站惡補!!! Angry


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:ymshin]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2003-07-20 16:18 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
不過我覺得挺奇怪的是
為什麼文中的code都是這樣寫的
1
2
3
4
5
6
7
8
9
10
11
12
13
class SomeClass {
  private Resource resource = null;
 
  public Resource getResource() {
    if (resource == null) {
      synchronized {
        if (resource == null) 
          resource = new Resource();
      }
    }
    return resource;
  }
}

synchronzied後面為什麼沒有說lock哪個物件??

然後在第一篇What does synchronized really mean? 這一段的最後又說:

Only when threads A and B synchronize on the same object will the JMM guarantee that thread B sees the changes made by thread A, and that changes made by thread A inside the synchronized block appear atomically to thread B (either the whole block executes or none of it does.)

那如果我們lock都是
SomeClass.class的話...
那是不是還是可以用DCL呢??

我想問題應該越來越清楚了...
因為每個Architecture底層的Memory Model不同
應該說memory consistency model不同
越relax的方法是可以越快... 減少synchronization的overhead...
越strict的方法可以越能保證不會有inconsistent的問題...CPU也好設計
而這個DCL問題應該是出現在較ralax的architecture上的
在某些model中是允許看到critical section中還未initiate的instance
但是我覺得上面的JVM本身就要顧及到對synchronized的實作是否能夠符合synchronized的sementic才對
還有這篇的出發點倒是抵是lock哪個物件也看不出來
因為就如我上面講的... 它的code怪怪的... 到底是lock哪個物件??
是singleton的物件嘛?? 還是SomeClass.class??
這邊有點暗晦不明
也請各為板友頻論一下我是不是有說到重點??


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:Biologic]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2003-07-20 16:34 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Biologic wrote:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void setInstance(Singleton si) {
  instance=si;
}
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        
        }
        setInstance(inst);               //5
      }
    }
  }
  return instance;
}

不知道有沒有效...?? 我總覺得 //3 是多餘的...

i agree with u
我也覺得//3是多餘的
哪有對同一個物件取得兩次lock阿...
就像我已經追到我馬子了
我又去追一次我馬子
廢話...當然成功阿...因為他已經是你馬子了
所以我覺得是多此一舉啦..

還是我對synchronized有誤解??


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:popcorny]
ymshin





發文: 277
積分: 4
於 2003-07-20 17:00 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
popcorny wrote:
不過我覺得挺奇怪的是
為什麼文中的code都是這樣寫的
1
2
3
4
5
6
7
8
9
10
11
12
13
class SomeClass {
  private Resource resource = null;
 
  public Resource getResource() {
    if (resource == null) {
      synchronized {
        if (resource == null) 
          resource = new Resource();
      }
    }
    return resource;
  }
}



那好像是 DCL idiom 的原型, 之後是大家針對它的問題一邊修正一邊討論的
過程, 最後才放棄宣佈它有問題不能被修正拿來用.


synchronzied後面為什麼沒有說lock哪個物件??

然後在第一篇What does synchronized really mean? 這一段的最後又說:

Only when threads A and B synchronize on the same object will the JMM guarantee that thread B sees the changes made by thread A, and that changes made by thread A inside the synchronized block appear atomically to thread B (either the whole block executes or none of it does.)

那如果我們lock都是
SomeClass.class的話...
那是不是還是可以用DCL呢??

我想問題應該越來越清楚了...
因為每個Architecture底層的Memory Model不同
應該說memory consistency model不同
越relax的方法是可以越快... 減少synchronization的overhead...
越strict的方法可以越能保證不會有inconsistent的問題...CPU也好設計
而這個DCL問題應該是出現在較ralax的architecture上的
在某些model中是允許看到critical section中還未initiate的instance
但是我覺得上面的JVM本身就要顧及到對synchronized的實作是否能夠符合synchronized的sementic才對
還有這篇的出發點倒是抵是lock哪個物件也看不出來
因為就如我上面講的... 它的code怪怪的... 到底是lock哪個物件??
是singleton的物件嘛?? 還是SomeClass.class??
這邊有點暗晦不明
也請各為板友頻論一下我是不是有說到重點??


看到一篇資料有點舊, 不過大致說明了 synchronization 的用法. 雖然部分和現今有些出入, 對於瞭解運作是蠻好的入門文章.

"How the Java virtual machine performs thread synchronization"
http://www.javaworld.com/javaworld/jw-07-1997/jw-07-hood_p.html

不過 JMM 的做法現在不一樣了; 以前這種方式可能就是為什麼執行過慢的緣故
.

那個日文版被我發現有英文版說~~~不好意思~~~就是不知台灣 IBM 有沒有
翻譯... ^^"

hehehe~我喜歡 javaworld 的 searching engine 和文章, 寫的比 Sun 的容易
懂而且有一定的權威性~~~大家有空也去挖挖寶. Big Smile


ymshin edited on 2003-07-20 17:04
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:koji]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2003-07-20 17:28 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
koji wrote:
在Sun JDK 1.2.1 JIT compiler下所產生的assembly code如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;asm code generated for getInstance
054D20B0   mov         eax,[049388C8]      ;load instance ref
054D20B5   test        eax,eax             ;test for null
054D20B7   jne         054D20D7
054D20B9   mov         eax,14C0988h
054D20BE   call        503EF8F0            ;allocate memory
054D20C3   mov         [049388C8],eax      ;store pointer in 
                                           ;instance ref. instance  
                                           ;non-null and ctor
                                           ;has not run
054D20C8   mov         ecx,dword ptr [eax] 
054D20CA   mov         dword ptr [ecx],1   ;inline ctor - inUse=true;
054D20D0   mov         dword ptr [ecx+4],5 ;inline ctor - val=5;
054D20D7   mov         ebx,dword ptr ds:[49388C8h]
054D20DD   jmp         054D20B0


可以看到在054D20C3部分將會讓instance變成非null,但是並沒有執行constructor,因此在此狀態下會產生double-checked locking的破綻.

所以在C3到完成建構之間有其他動作從中切入,double-checked locking將會失敗

看了以後在翻,翻的有點爛,請多指教Q_Q

謝謝版友的連結又讓我學的更詳細很多呵呵

仔細看了這段bytecode我產生了一個疑問
compile產生的code應該有問題吧...
是先做assignment再做contructor嘛??
還是先做contructor再做assignment呢??
這段bytecode是前者
不過我覺得是後者才是正確....

但是就算compile產生的是後者
還是有可能在multiple cpu時造成問題
下面就是我的解釋

沒錯
bytecode是先做contructor再做assignment
但是在multiple CPU的環境之下
CPU執行時是re-order過的..
他會先做assginment再做constructor..
這是因為CPU在做pipeline時
發現沒有data hazard (這個請自己去翻architecture的書)
就把做assignment的operation交給另一個CPU做
結果assignment搶先了...
但是constructor還沒做完...
此時呢? 另一個thread進來了..
由於沒在sync block中..
所以他直接判斷是否resource為null
發現不是(因為已經做assignment了...)
結果就回傳一個還未初始畫結束的instance回去
錯誤就在此產生了...

結論:
這個情況應該只出現再多CPU的情況下
因為單CPU下 程式執行的順序就跟程式的順序一樣...
但是多CPU的話.. 為了加快速度...
會有較relax的memory consistency model
而造成一些out of order的程式執行順序
DCL就在這個情況下產生了錯誤


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:popcorny]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-20 18:20 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
popcorny wrote:
仔細看了這段bytecode我產生了一個疑問
compile產生的code應該有問題吧...
是先做assignment再做contructor嘛??
還是先做contructor再做assignment呢??
這段bytecode是前者
不過我覺得是後者才是正確....

但是就算compile產生的是後者
還是有可能在multiple cpu時造成問題
下面就是我的解釋

沒錯
bytecode是先做contructor再做assignment
但是在multiple CPU的環境之下
CPU執行時是re-order過的..
他會先做assginment再做constructor..
這是因為CPU在做pipeline時
發現沒有data hazard (這個請自己去翻architecture的書)
就把做assignment的operation交給另一個CPU做
結果assignment搶先了...
但是constructor還沒做完...
此時呢? 另一個thread進來了..
由於沒在sync block中..
所以他直接判斷是否resource為null
發現不是(因為已經做assignment了...)
結果就回傳一個還未初始畫結束的instance回去
錯誤就在此產生了...

結論:
這個情況應該只出現再多CPU的情況下
因為單CPU下 程式執行的順序就跟程式的順序一樣...
但是多CPU的話.. 為了加快速度...
會有較relax的memory consistency model
而造成一些out of order的程式執行順序
DCL就在這個情況下產生了錯誤


奇怪... 我找不到 JIT.
另外 java bytecodes 有機會被分解成 machine codes 嗎? 我很好奇ㄝ~~
還有 P2 (pro+) 內部都是採用 out-of-order execution. 很難掌握實際被執行的順序(or 結束順序...)... 另外如果下面的情況發生在 系統內... (multi-thread)

main thread 在建立 singleton 物件時先建立一個 thread, 且同時還有很多 singleton objects 還沒有被 initialized. main thread 可能還在做 object initialization, 剛好只有 allocate space, 但是 constructor 還沒有被執行... 同時又剛好那 second thread 讀取或使用這 singleton object 的資料... 這樣不也是種錯誤??

我似乎有點像是在鬧局的~~ Big Smile


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:popcorny]
koji

秒速5センチメートル

站長

發文: 8415
積分: 19
於 2003-07-20 20:23 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
http://wwws.sun.com/software/solaris/jit/

另外文章中的assembly code並不是由我實際測試執行出來
在文章中他是明確的說明會產生那樣的assembly code
所以在multithread下
DCL會產生問題

他整篇文章就是提到
很有可能妳雖然allocate space,讓它變成非null
但是並沒完成constructor 的動作,所以才會出問題

付上英文版的網址
http://www-106.ibm.com/developerworks/java/library/j-dcl.html
我想我應該沒有翻錯才對Dead

koji

--
偷偷改一下,搞錯名詞>.<


koji edited on 2003-07-20 23:17
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:koji]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-20 21:39 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
koji wrote:
http://wwws.sun.com/software/solaris/jit/

另外文章中的bytecode並不是由我實際測試執行出來
在文章中他是明確的說明會產生那樣的bytecode
所以在multithread下
DCL會產生問題

他整篇文章就是提到
很有可能妳雖然allocate space,讓它變成非null
但是並沒完成constructor 的動作,所以才會出問題

付上英文版的網址
http://www-106.ibm.com/developerworks/java/library/j-dcl.html
我想我應該沒有翻錯才對Dead

koji


(你應該是回我, first thx for JIT compiler)
jit 產生的應該是 machine codes.
我是指在 JVM 執行的 bytecodes 應該沒有被轉成 machine codes 來執行.

另外我指的案例是指系統剛剛啟動情況下....
如果大家都用 private Singleton instance=new Singleton();... 這不一樣也會發生問題嗎??

我越看越像是 我在找砸~~


Biologic edited on 2003-07-20 22:10
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:popcorny]
koji

秒速5センチメートル

站長

發文: 8415
積分: 19
於 2003-07-20 22:14 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
妳的第二個問題我還是看不太懂A_A
什麼叫做
系統剛剛啟動情況下....
如果大家都用 private Singleton instance=new Singleton();... 這不一樣也會發生問題嗎??

是說放成

public class Singleton{
private static Singleton instance=new Singleton();
private Singleton()
{}
}
這樣的狀況下??

koji


koji edited on 2003-07-20 22:21
reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:koji]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2003-07-20 22:45 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
koji wrote:
妳的第二個問題我還是看不太懂A_A
什麼叫做
系統剛剛啟動情況下....
如果大家都用 private Singleton instance=new Singleton();... 這不一樣也會發生問題嗎??

是說放成

public class Singleton{
private static Singleton instance=new Singleton();
private Singleton()
{}
}
這樣的狀況下??

koji


設有一個 singleton thread, 然後在他的 runtime code 裡面會用到其他的 singleton objects.... 不知道 JVM 有沒有對應機制?


reply to postreply to post
作者 Re:[DP]Singleton pattern, Double-checked Locking pattern (by Biologic) [Re:ymshin]
william





發文: 49
積分: 4
於 2003-08-03 02:36 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
ymshin wrote:
我灌一下水好了, 順便湊一下作業的篇數~Big Smile

簡單說也就是 DCL 的設計基礎有問題; 它是假設所有 threads 處理是經由循序
方式一個個排隊等著執行, 可是實際上的處理為了執行效能並不是如此動作;


關於 DCL, 目前有一篇由幾位巨頭聯名的定案文章,
或許可對這主題蓋棺論定:

The "Double-Checked Locking is Broken" Declaration
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html


reply to postreply to post
go to first page go to previous page  1   2  go to next page go to last page
» JWorld@TW »  Software Design » GoF

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8