缓存实例
问题描述:
我只是对java内存模型有点好奇。缓存实例
这是我虽然。
如果我有下面的类
public class Test {
int[] numbers = new int[Integer.MAX_VALUE]; // kids dont try this at home
void increment(int ind){
numbers[ind]++;
}
int get(int ind){
return numbers[ind];
}
}
有多个读者get()和访问该类一个作家增量()线程。
问题是在这里,实际上是否有任何同步,我必须做的,为了让每个方法调用后的类保持一致的状态?
为什么我问这个问题,我很好奇数组中的元素是由JVM以某种方式缓存还是只适用于类成员?如果数组内的成员可以被缓存,有没有办法将它们定义为volatile?
感谢 罗马
答
为了确保数据在方法调用后保持一致的状态,您肯定必须使用某种同步(无论是在您的类还是基础数据结构上)。考虑以下情况,使用两个线程A和B,最初包含所有零值的整数数组。
- 线程A调用增量(0)。后增加操作不是原子的;您实际上可以将其分解为至少三个步骤:
- 读取当前值;向当前值添加一个;存储值。
- 线程B还调用increment(0)。如果在线程A完成相同操作后马上发生这种情况,它们都将读取相同的初始值,以获取阵列索引0处的元素。
- 在这一点上,线程A和B都已经为它们想要增加的元素读取了'0'值。两者都会将值增加到'1'并将其存储回数组的第一个元素中。
- 因此,只有线程的工作最后写入到阵列才能看到。
如果您有decrement()
方法,情况类似。如果increment()
和decrement()
两个线程几乎同时被调用,则不知道结果会是什么。该值将增加1或减少1,操作不会相互“取消”。
编辑:更新,以反映低于
对不起,我罗马人(OP)评论误读职务。我想我明白你的问题,这是沿着线:
“如果我声明数组作为
volatile
, 是否意味着访问它的元素 被视为volatile
以及”
快速回答是否:请参阅this article for more information;以前答案中的信息也是正确的。
答
是,虚拟机被允许的线程内缓存未同步或voltile任何领域。为了防止这种情况,你可以可能将这些字段标记为volatile,但它们仍然不会是线程安全的,因为++不是原子操作。将synchronized关键字添加到方法中,并且您很安全。
你们都是对的,这是纯java内存模式的问题,而不是同步。我知道类的同步会完成这项工作,或者原子整数数组可以完美地完成这项工作。但我的问题是JVM是否会缓存数组的实际成员。它意味着数组[0]的成员定义为与volotile一样好? – Roman 2009-07-20 13:19:09
如果这是一个单线程,那么不需要担心同步问题,是吗? – 2009-07-20 14:33:41
单写线程,多个阅读器 – Roman 2009-07-20 15:21:03