Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在同一函数中的synchronized()块中初始化后,Java集合能否在synchronized()之外安全使用?_Java_Concurrency_Thread Safety - Fatal编程技术网

在同一函数中的synchronized()块中初始化后,Java集合能否在synchronized()之外安全使用?

在同一函数中的synchronized()块中初始化后,Java集合能否在synchronized()之外安全使用?,java,concurrency,thread-safety,Java,Concurrency,Thread Safety,以下代码是否被认为是线程安全的,即:写入列表是否保证在读取列表之前发生?我一直在试图理解这在Java内存模型中是否被认为是安全的,但还不清楚 通过基本流分析,似乎可以保证所有可能的线程在点击下面的for循环之前都必须通过synchronized初始化程序块,但是对该列表的迭代是否具有确定性和线程安全性?我不确定在使用下面的列表之前是否保证进行初始化 假设这是类中唯一的方法。我知道在同步块中移动迭代可以保证线程安全,但我更感兴趣的是知道这个构造是否安全 另外,假设列表从未逃过类 Java内存模型在

以下代码是否被认为是线程安全的,即:写入列表是否保证在读取列表之前发生?我一直在试图理解这在Java内存模型中是否被认为是安全的,但还不清楚

通过基本流分析,似乎可以保证所有可能的线程在点击下面的
for
循环之前都必须通过
synchronized
初始化程序块,但是对该列表的迭代是否具有确定性和线程安全性?我不确定在使用下面的列表之前是否保证进行初始化

假设这是类中唯一的方法。我知道在同步块中移动迭代可以保证线程安全,但我更感兴趣的是知道这个构造是否安全

另外,假设列表从未逃过类

Java内存模型在JLS中解释如下:

私有列表;
私有最终对象监视器=新对象();
公共空白栏(){
同步(监视器){
if(list==null){
列表=新的ArrayList();
list.add(…);//昂贵的操作
list.add(…);//昂贵的操作
list.add(…);//昂贵的操作
}
}
for(Foo-Foo:list){
//和福做点什么
}
}

如果您不再从同步方法中修改列表,那么您公开的代码是安全的。
现在,如果其他方法(不是bar())使用相同的列表,那么您的代码是不安全的。另外,您应该声明
最终列表
它是线程安全的当且仅当
这是您在结构上修改列表的唯一地方

如果您在其他地方修改列表(例如使用
clear()
),即使其他地方也使用
synchronized
,那么在迭代列表时也可以轻松修改列表

如果您不打算在其他任何地方修改列表,那么使用来确保(并记录)这一事实可能是一个好主意。

同步的
列表(list)
仅适用于其中包含的代码块。如果另一个线程在您使用for each循环遍历列表时修改列表,则会出现问题。

保证:

监视器上的解锁发生在监视器上的每个后续锁定之前

它还保证同步块不能并发执行,也不能用for循环重新排序

因此,到达并获取监视器的第一个线程(我们称之为T0)将初始化列表。当T0退出同步块时,线程内语义保证for循环将按照T0中的预期执行

随后到达的所有线程将等待监视器可用,获取它,并且由于上面的保证,将看到由T0初始化的列表(即不为null并填充)。由于线程内语义,for循环将按预期执行


结论:如果您的列表没有在其他地方写入,并且所有读取都在获取监视器后完成,则您的代码是安全的。

我已经对假设列表不会逃逸课堂的问题进行了澄清。请注意-我正在寻找JLS内存模型方面的答案!您可能希望将
监视器
设为最终版
。我已更新了问题,以反映您在此处注意到的未初始化值,因为我不想分散对内存模型问题的注意力。@Sliphed:我已删除了答案的这一部分。
private List<Foo> list;
private final Object monitor = new Object();

public void bar() {
    synchronized (monitor) {
        if (list == null) {
            list = new ArrayList<>();
            list.add(...); // expensive operation
            list.add(...); // expensive operation
            list.add(...); // expensive operation
        }
    }

    for (Foo foo : list) {
        // do something with foo
    }
}