在javaeye有位朋友问了我一个非常好的问题。
问题
一个线程向volatile的数组中设置值,而另一个线程向volatile的数组中读取。
比如seg.setValue(2),随后另一个线程调用seg.getValue(2),前一个线程设置的值对读取的线程是可见的吗?
我看书上说volatile的数组只针对数组的引用具有volatile的语义,而不是它的元素。
ConcurrentHashMap中也有这样的代码,我很疑惑,希望得到你的解答,谢谢。
01 |
public class Seg {
|
02 |
03 |
private volatile Object[] tabs = new Object[ 10 ];
|
04 |
05 |
public void setValue( int index) {
|
06 |
tabs[index] = new Object();
|
07 |
} |
08 |
09 |
public Object getValue( int index) {
|
10 |
return tabs[index];
|
11 |
} |
12 |
} |
我的回答
我做了实验证实这句话是正确的,“volatile的数组只针对数组的引用具有volatile的语义,而不是它的元素”。
测试代码如下:
private static volatile Object[] tabs = new Object[10];
public static void main(String[] args) {
tabs[0]=1;
tabs=new Object[10];
}
编译成汇编语句如下
001 |
Java HotSpot(TM) Client VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output |
002 |
CompilerOracle: compileonly *ArrayTest.main |
003 |
Loaded disassembler from D:\java\jdk1.6.0_33\jre\bin\client\hsdis-i386.dll |
004 |
Decoding compiled method 0x009ec7c8: |
005 |
Code: |
006 |
[Disassembling for mach='i386'] |
007 |
[Entry Point] |
008 |
[Verified Entry Point] |
009 |
[Constants] |
010 |
# {method} 'main' '([Ljava/lang/String;)V' in 'volatileTest/ArrayTest' |
011 |
# parm0: ecx = '[Ljava/lang/String;' |
012 |
# [sp+0x30] (sp of caller) |
013 |
0x009ec8e0: mov %eax,-0x3000(%esp) |
014 |
0x009ec8e7: push %ebp |
015 |
0x009ec8e8: sub $0x28,%esp |
016 |
0x009ec8eb: mov $0x32aa1eb0,%esi ; {oop('volatileTest/ArrayTest')} |
017 |
0x009ec8f0: mov 0x150(%esi),%edi ;*getstatic tabs |
018 |
; - volatileTest.ArrayTest::main@0 (line 7) |
019 |
0x009ec8f6: mov $0x1,%ecx ;*invokestatic valueOf |
020 |
; - volatileTest.ArrayTest::main@5 (line 7) |
021 |
0x009ec8fb: mov %esi,0x14(%esp) |
022 |
0x009ec8ff: mov %edi,0x10(%esp) |
023 |
0x009ec903: call 0x009ad340 ; OopMap{[20]=Oop [16]=Oop off=40} |
024 |
;*invokestatic valueOf |
025 |
; - volatileTest.ArrayTest::main@5 (line 7) |
026 |
; {static_call} |
027 |
0x009ec908: mov 0x10(%esp),%edi |
028 |
0x009ec90c: lea 0xc(%edi),%ebx |
029 |
0x009ec90f: cmpl $0x0,0x8(%edi) ; implicit exception: dispatches to 0x009eca07 |
030 |
0x009ec916: jbe 0x009eca11 |
031 |
0x009ec91c: cmp $0x0,%eax |
032 |
0x009ec91f: je 0x009ec960 |
033 |
0x009ec925: mov 0x4(%edi),%edx ; implicit exception: dispatches to 0x009eca1d |
034 |
0x009ec928: mov 0x4(%eax),%esi |
035 |
0x009ec92b: mov 0x88(%edx),%edx |
036 |
0x009ec931: cmp %edx,%esi |
037 |
0x009ec933: je 0x009ec960 |
038 |
0x009ec939: mov 0x10(%edx),%edi |
039 |
0x009ec93c: cmp (%esi,%edi,1),%edx |
040 |
0x009ec93f: je 0x009ec960 |
041 |
0x009ec945: cmp $0x14,%edi |
042 |
0x009ec948: jne 0x009eca22 |
043 |
0x009ec94e: push %esi |
044 |
0x009ec94f: push %edx |
045 |
0x009ec950: call 0x009ebb40 ; {runtime_call} |
046 |
0x009ec955: pop %esi |
047 |
0x009ec956: pop %edx |
048 |
0x009ec957: cmp $0x0,%edx |
049 |
0x009ec95a: je 0x009eca22 |
050 |
0x009ec960: mov %eax,(%ebx) |
051 |
0x009ec962: shr $0x9,%ebx |
052 |
0x009ec965: movb $0x0,0x28eb100(%ebx) ;*aastore |
053 |
; - volatileTest.ArrayTest::main@8 (line 7) |
054 |
0x009ec96c: mov $0xa,%ebx |
055 |
0x009ec971: mov $0x37a0e380,%edx ; {oop('java/lang/Object'[])} |
056 |
0x009ec976: mov %ebx,%edi |
057 |
0x009ec978: cmp $0xffffff,%ebx |
058 |
0x009ec97e: ja 0x009eca27 |
059 |
0x009ec984: mov $0x13,%esi |
060 |
0x009ec989: lea (%esi,%ebx,4),%esi |
061 |
0x009ec98c: and $0xfffffff8,%esi |
062 |
0x009ec98f: mov %fs:0x0(,%eiz,1),%ecx |
063 |
0x009ec997: mov -0xc(%ecx),%ecx |
064 |
0x009ec99a: mov 0x34(%ecx),%eax |
065 |
0x009ec99d: lea (%eax,%esi,1),%esi |
066 |
0x009ec9a0: cmp 0x3c(%ecx),%esi |
067 |
0x009ec9a3: ja 0x009eca27 |
068 |
0x009ec9a9: mov %esi,0x34(%ecx) |
069 |
0x009ec9ac: sub %eax,%esi |
070 |
0x009ec9ae: movl $0x1,(%eax) |
071 |
0x009ec9b4: mov %edx,0x4(%eax) |
072 |
0x009ec9b7: mov %ebx,0x8(%eax) |
073 |
0x009ec9ba: sub $0xc,%esi |
074 |
0x009ec9bd: je 0x009ec9e3 |
075 |
0x009ec9c3: xor %ebx,%ebx |
076 |
0x009ec9c5: shr $0x3,%esi |
077 |
0x009ec9c8: jae 0x009ec9d8 |
078 |
0x009ec9ce: mov %ebx,0xc(%eax,%esi,8) |
079 |
0x009ec9d2: je 0x009ec9e3 |
080 |
0x009ec9d8: mov %ebx,0x8(%eax,%esi,8) |
081 |
0x009ec9dc: mov %ebx,0x4(%eax,%esi,8) |
082 |
0x009ec9e0: dec %esi |
083 |
0x009ec9e1: jne 0x009ec9d8 |
084 |
0x009ec9e3: mov 0x14(%esp),%esi |
085 |
0x009ec9e7: mov %eax,0x150(%esi) |
086 |
0x009ec9ed: shr $0x9,%esi |
087 |
0x009ec9f0: movb $0x0,0x28eb100(%esi) |
088 |
0x009ec9f7: lock addl $0x0,(%esp) ;*putstatic tabs |
089 |
; - volatileTest.ArrayTest::main@14 (line 9) |
090 |
0x009ec9fc: add $0x28,%esp |
091 |
0x009ec9ff: pop %ebp |
092 |
0x009eca00: test %eax,0x950100 ; {poll_return} |
093 |
0x009eca06: ret |
094 |
0x009eca07: call 0x009ea4d0 ; OopMap{[20]=Oop eax=Oop edi=Oop off=300} |
095 |
;*aastore |
096 |
; - volatileTest.ArrayTest::main@8 (line 7) |
097 |
; {runtime_call} |
098 |
0x009eca0c: call 0x009ea4d0 ; OopMap{[20]=Oop eax=Oop edi=Oop off=305} |
099 |
;*aastore |
100 |
; - volatileTest.ArrayTest::main@8 (line 7) |
101 |
; {runtime_call} |
102 |
0x009eca11: movl $0x0,(%esp) |
103 |
0x009eca18: call 0x009ea1d0 ; OopMap{[20]=Oop eax=Oop edi=Oop off=317} |
104 |
;*aastore |
105 |
; - volatileTest.ArrayTest::main@8 (line 7) |
106 |
; {runtime_call} |
107 |
0x009eca1d: call 0x009ea4d0 ; OopMap{[20]=Oop eax=Oop off=322} |
108 |
;*aastore |
109 |
; - volatileTest.ArrayTest::main@8 (line 7) |
110 |
; {runtime_call} |
111 |
0x009eca22: call 0x009eb850 ; OopMap{[20]=Oop eax=Oop off=327} |
112 |
;*aastore |
113 |
; - volatileTest.ArrayTest::main@8 (line 7) |
114 |
; {runtime_call} |
115 |
0x009eca27: call 0x009eb1c0 ; OopMap{[20]=Oop off=332} |
116 |
;*anewarray |
117 |
; - volatileTest.ArrayTest::main@11 (line 9) |
118 |
; {runtime_call} |
119 |
0x009eca2c: jmp 0x009ec9e3 |
120 |
0x009eca2e: nop |
121 |
0x009eca2f: nop |
122 |
0x009eca30: mov %fs:0x0(,%eiz,1),%esi |
123 |
0x009eca38: mov -0xc(%esi),%esi |
124 |
0x009eca3b: mov 0x184(%esi),%eax |
125 |
0x009eca41: movl $0x0,0x184(%esi) |
126 |
0x009eca4b: movl $0x0,0x188(%esi) |
127 |
0x009eca55: add $0x28,%esp |
128 |
0x009eca58: pop %ebp |
129 |
0x009eca59: jmp 0x009bb5c0 ; {runtime_call} |
130 |
0x009eca5e: hlt |
131 |
0x009eca5f: hlt |
132 |
[Stub Code] |
133 |
0x009eca60: nop ; {no_reloc} |
134 |
0x009eca61: nop |
135 |
0x009eca62: mov $0x0,%ebx ; {static_stub} |
136 |
0x009eca67: jmp 0x009eca67 ; {runtime_call} |
137 |
[Exception Handler] |
138 |
0x009eca6c: call 0x009eb600 ; {runtime_call} |
139 |
0x009eca71: push $0x6db038d4 ; {external_word} |
140 |
0x009eca76: call 0x009eca7b |
141 |
0x009eca7b: pusha |
142 |
0x009eca7c: call 0x6da09de0 ; {runtime_call} |
143 |
0x009eca81: hlt |
144 |
[Deopt Handler Code] |
145 |
0x009eca82: push $0x9eca82 ; {section_word} |
146 |
0x009eca87: jmp 0x009ad970 ; {runtime_call} |
可以看到line 7给数组的某个元素赋值时没有lock前缀的指令。
而修改数组line 9才有lock前缀的指令。
1 |
0x009ec9f7: lock addl $0x0,(%esp) ;*putstatic tabs |
2 |
; - volatileTest.ArrayTest::main@14 (line 9) |
时间: 2025-01-21 06:20:50