volatile是否能保证数组中元素的可见性?

在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

volatile是否能保证数组中元素的可见性?的相关文章

jquery获得div数组中元素的id的方法

问题描述 jquery获得div数组中元素的id的方法 我把多个div都放在数组里,我该怎么使用$操作符来把数组元素赋给一个新变量?普通情况是var div = $(''#div1''),我这种情况该怎么写? 解决方案 var divarr=[]; for(var i=0;i<divarr.length;i++){ var div = $(divarr[i]); } 解决方案二: var arr=['div1','div2','div3']; for(var i=0;i<arr.length;

根据一个数组中重复的元素,取出对应数组中元素

问题描述 近来遇到了点问题,请教大家下,希望给个答案,谢谢.需求(根据一个数组中重复的元素,取出对应数组中元素):有两个对应的数组:A={1,2,3,4,5},A1={a,b,a,b,c}根据数组A1中的重复原素来取出数组A中对应的元素,并且累加成字符串:1,3根据数组A1中的重复原素来取出数组A中对应的元素,并且累加成字符串:2,4根据数组A1中的不重复的元素取出数组A中对应的元素,并且累加成字符串:2,5以此类推.谢谢. 解决方案 解决方案二:首先两个数组长度相同那么索引必然也一样你只需要知

lnk1179-怎么统计一个数组中元素的频率,和出现频率最高的元素

问题描述 怎么统计一个数组中元素的频率,和出现频率最高的元素 hshxjjnnn.hajhshhajsjsjsjsjsjxmdmdndb char ch[N] cin>>ch [], 解决方案 只能一个个字符遍历,然后记录下每个字符出现的次数 #include<iostream> #include <stdio.h> #include <ctype.h> using namespace std; int main(){ int a[26]={0}; int

MFC写图像处理程序,现有很多个像素点要进行处理,每个像素点都要遍历同一数组中元素并获的一个值

问题描述 MFC写图像处理程序,现有很多个像素点要进行处理,每个像素点都要遍历同一数组中元素并获的一个值 现在想用多线程加速要如何做呢?因为要处理很多点,用单线程太慢了,求高手指点 解决方案 你这个任务,采用多线程或者单线程时间都一样! 解决方案二: 多个线程,每个线程处理一部分像素点.相当于分配任务 解决方案三: 创建多个线程,给线程分配一部分像素点,主线程等待所有任务线程完成,这里可以显示"处理中"对话框,然后把处理结果汇总起来就行啦

PHP中unset,array_splice删除数组中元素的区别_php技巧

如果要在某个数组中删除一个元素,可以直接用的unset,但是数组的索引不会重排: <?php $arr = array('a','b','c','d'); unset($arr[1]); print_r($arr); ?> 结果是: Array ( [0] => a [2] => c [3] => d )   那么怎么才能做到缺少的元素会被填补并且数组会被重新索引呢?答案是array_splice(): <?php $arr = array('a','b','c','d

Java中如何比较两个数组中元素是否相同_java

呵呵呵,实现Java比较两个数组中的元素是否相同的功能你是怎么做的?看下面最简单方法: 复制代码 代码如下: import java.util.Arrays; public class Test { /** * Java比较两个数组中的元素是否相同 */ public static void main(String[] args) { String [] array1 = {"1","2","3"}; String [] array2 = {&q

如何判断数组中元素是否完全不同

如何判断一个4*4的数组中所有的元素都不相同,一个4*4的二维数组,判断数组中每个元素是否相同 如相同就返回0 都不相同就返回1 int fun(int a[4][4]) { int i = 0, j = 0; int m = 0, n = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (m = i; m < 4; m++) { for (n = j + 1; n < 4; n++) { if (a[i][j]

C语言将数组中元素的数排序输出的相关问题解决_C 语言

 问题描述:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个.例如输入数组{32,  321},则输出这两个能排成的最小数字32132.请给出解决问题的算法,并证明该算法.       思路:先将整数数组转为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可.这里注意的是字符串的比较函数需要重新定义,不是比较a和b,而是比较ab与 ba.如果ab < ba,则a < b:如果ab > ba,则a > b:如果ab = ba,则a = b.比

asp 得到动态数组中元素的个数_应用技巧

一个动态数组 a,如果你已经使用redim 语句给它设定了大小,那么在此之后使用 ubound(a) 就可以得到它的上边界. 如果你没有使用 redim 语句给它设定大小,直接使用 ubound(a) 函数,那么运行时会报错,并会中断程序的执行.我们恰恰利用这一点,可以知道这个数组还没有任何元素.于此同时,我们却不想程序中断执行,那么可以在 ubound(a) 函数执行前加上一句 复制代码 代码如下: on error resume next 把本功能写成一个函数 function get_el