首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java不可变数组线程安全性

Java不可变数组线程安全性
EN

Stack Overflow用户
提问于 2011-07-08 22:40:40
回答 3查看 1.8K关注 0票数 10

我有一个关于Java内存模型的问题。下面是一个简单的类,展示了这个问题:

代码语言:javascript
复制
public class ImmutableIntArray {

    private final int[] array;

    public ImmutableIntArray() {
        array = new int[10];
        for (int i = 0; i < 10; i++) {
            array[i] = i;
        }
    }

    // Will always return the correct value?
    public int get(int index) {
        return array[index];
    }

}

据我所知,JMM保证final字段的值在构造后对其他线程可见。但我希望确保其他线程在构造后能看到存储在数组中的最新版本的数据。

当然上面的代码只是一个简单的例子来说明这个问题,实际上我想为直接的字节缓冲区实现一个简单的缓存,我不想依赖一些Collection类。目前,我正在使用ReentrantReadWriteLock来确保正确的行为,但如果可能的话,我希望避免使用它。

EN

回答 3

Stack Overflow用户

发布于 2011-07-09 00:06:42

你的例子不太正确。为了获得最终的现场保证,您需要:

代码语言:javascript
复制
public ImmutableIntArray() {
    int tmparray = new int[10];
    for (int i = 0; i < 10; i++) {
        tmparray[i] = i;
    }
    array = tmparray;
}
票数 3
EN

Stack Overflow用户

发布于 2011-07-09 00:17:11

我确实认为,数组的语义与对象的最终引用具有相同的语义。规格说明

一个线程只能在对象完全初始化后才能看到对该对象的引用,它可以保证看到该对象的最终字段的正确初始化值。

它还说

它还将看到那些最终字段引用的任何对象或数组的版本,这些最终字段至少与最终字段一样是最新的。

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.5

票数 2
EN

Stack Overflow用户

发布于 2014-12-12 22:24:13

我认为您的数组更改将在您的ImmutableIntArray中可见。根据我对JLS的阅读,冻结操作应该在构造器退出时发生。我认为临时数组的使用是无用的:

代码语言:javascript
复制
int tmparray = new int[10];
for (int i = 0; i < 10; i++) {
    tmparray[i] = i;
}
array = tmparray;

为了获得最终的字段保证,我们需要在构造器退出之前的某个地方冻结:

代码语言:javascript
复制
int tmparray = new int[10];
for (int i = 0; i < 10; i++) {
    tmparray[i] = i;
}
array = tmparray;
[freeze]

不管怎样,freeze会打开门来重新排序上面的指令,所以我们会得到同样的结果:

代码语言:javascript
复制
int tmparray = new int[10];
array = tmparray; 
for (int i = 0; i < 10; i++) {
    tmparray[i] = i;
}
[freeze]

freeze被实现为至少包含一个StoreStore。此StoreStore屏障必须在发布构造的实例之前发布。

来自JSR-133 Cookbook

您不能将构造函数内的finals存储区下移到构造函数外部的存储区下,这可能会使该对象对其他线程可见。(如下所示,这可能还需要发布一个屏障)。类似地,您不能对前两个中的任何一个进行重新排序,第三个赋值为: v.afield = 1;x.finalField = v;...;sharedRef = x;

我认为这是由(JSR-133 Cookbook)完成的

在所有存储之后,但在从任何构造函数返回任何带有StoreStore字段的类之前,都会发出最终屏障。

所以我们不能在所有其他建筑商店完成之前在sharedRef中进行存储。

您可以在(JSR133 spec)中通过:“来自最终字段的传递保证”进行搜索。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6626079

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档