JAvaにおけるDouble-Checked Locking二重ロックのテストコード

5403 ワード

JAvaにおけるDouble-Checked Locking二重ロックのテストコード
 
 1 
package
 test;
 2 
 3 
public
 
class
 testClone {
 4 
    
volatile
 
boolean
 isInit;
 5 
 6 
    
volatile
 Foo foo;
 7 
 8 
    
volatile
 
int
 time 
=
 
1
;
 9 
10 
    
public
 
class
 Foo {
11 
        
volatile
 
int
 flg;
12 
13 
        
public
 Foo() {
14 
            flg 
=
 
0
;
15 
            
try
 {
16 
                Thread.sleep(time);
17 
            } 
catch
 (InterruptedException e) {
18 
            }
19 
            
++
flg;
20 
            System.out.println(
"
Foo inited
"
);
21 
        }
22 
    }
23 
24 
    
public
 
static
 
void
 main(String[] args) 
throws
 InterruptedException {
25 
        testClone t 
=
 
new
 testClone();
26 
        t.test();
27 
    }
28 
29 
    
public
 
void
 test() {
30 
        
for
 (
int
 i 
=
 
0
; i 
<
 
5

++
i) {
31 
            WorkThread t 
=
 
new
 WorkThread();
32 
            t.start();
33 
        }
34 
35 
        
for
 (;;) {
36 
            
try
 {
37 
                Thread.sleep(
1000
);
38 
            } 
catch
 (InterruptedException e) {
39 
            }
40 
            time 
=
 
1000
;
41 
            
synchronized
 (
this
) {
42 
                foo 
=
 
null
;
43 
            }
44 
        }
45 
    }
46 
47 
    
public
 Foo bar() {
48 
        Foo f 
=
 foo;
49 
        
if
 (f 
==
 
null
) {
50 
            
synchronized
 (
this
) {
51 
                
if
 (foo 
==
 
null
) {
52 
                    foo 
=
 
new
 Foo();
53 
                }
54 
                
return
 foo;
55 
            }
56 
        }
57 
        
return
 f;
58 
    }
59 
60 
    
public
 
class
 WorkThread 
extends
 Thread {
61 
        
public
 
void
 run() {
62 
            
for
 (;;) {
63 
                
try
 {
64 
65 
                    Foo f 
=
 bar();
66 
                    
if
 (f.flg 
==
 
0
) {
67 
                        System.out.println(f.flg);
68 
                    }
69 
                } 
catch
 (Throwable e) {
70 
                    e.printStackTrace();
71 
                }
72 
            }
73 
        }
74 
    }
75 
}
76 
1.4.2 jdkコンパイル実行.長時間実行すると、jit最適化によるFooの割り当てが完了すると、Fooコンストラクタが初期化されずにそのアドレスをfooに付与するというネット上のエラーは発見されませんでした.jitはコードを最適化したと信じています.Double-Checked Lockingに関する海外サイトの記事http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
A test case showing that it doesn't work
Paul Jakubik found an example of a use of double-checked locking that did not work correctly. A slightly cleaned up version of that code is available here.
When run on a system using the Symantec JIT, it doesn't work. In particular, the Symantec JIT compiles
singletons[i].reference = new Singleton();

to the following (note that the Symantec JIT using a handle-based object allocation system).
0206106A   mov         eax,0F97E78h
0206106F   call        01F6B210                  ; allocate space for
                                                 ; Singleton, return result in eax
02061074   mov         dword ptr [ebp],eax       ; EBP is &singletons[i].reference 
                                                ; store the unconstructed object here.
02061077   mov         ecx,dword ptr [eax]       ; dereference the handle to
                                                 ; get the raw pointer
02061079   mov         dword ptr [ecx],100h      ; Next 4 lines are
0206107F   mov         dword ptr [ecx+4],200h    ; Singleton's inlined constructor
02061086   mov         dword ptr [ecx+8],400h
0206108D   mov         dword ptr [ecx+0Ch],0F84030h

As you can see,the assignment to singletons[i].reference is performed before the constructor for Singleton is called.This is completely legal under the existing Java memory model,and also legal in C and C+(since neither of them have a memory model).上は海外サイトから与えられたjitコードと説明です.