Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
Java 对象的易失性和安全发布_Java_Multithreading - Fatal编程技术网

Java 对象的易失性和安全发布

Java 对象的易失性和安全发布,java,multithreading,Java,Multithreading,在少数文章中,它说volatile的使用修复了双重检查锁定问题 class Foo { private volatile Helper helper = null; public Helper getHelper() { if (helper == null) { synchronized(this) { if (helper == null)

在少数文章中,它说volatile的使用修复了双重检查锁定问题

class Foo {
        private volatile Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                synchronized(this) {
                    if (helper == null)
                        helper = new Helper(); //Important
                }
            }
            return helper;
        }
    }
但在这里,即使我们使用volatile for helper字段,这怎么可能是一个安全的发布呢?
我的意思是,这怎么能保证我们不会得到一致性帮助对象呢?

我认为这是因为JVM保留了
Helper=new Helper()
的顺序。我的意思是,只有在创建对象之后,分配才会发生。如果我错了,请纠正我。

我认为这是因为JVM保留了
helper=new helper()
的顺序。我的意思是,只有在创建对象之后,分配才会发生。如果我错了,请纠正我。

好的,同步部分之外的检查是为了避免不必要地进入监视器部分。如果您正在尝试优化性能,则可以省略该选项。只有在创建对象后无法将helper重置为null时,它才起作用。同步部分中的检查是为了避免不一致(因为在我们等待进入监视器时可能已经创建了对象)


synchronized的内部部分只能以互斥方式执行,这就是一致性的来源。但是,同样:如果(helper==null)外部
仅在helper在被分配了对helper实例的新引用后不能再变为null时才被允许。

好的,同步部分之外的检查是为了避免不必要地进入监视部分。如果您正在尝试优化性能,则可以省略该选项。只有在创建对象后无法将helper重置为null时,它才起作用。同步部分中的检查是为了避免不一致(因为在我们等待进入监视器时可能已经创建了对象)


synchronized的内部部分只能以互斥方式执行,这就是一致性的来源。但是,同样:外部
if(helper==null)
仅当helper在被分配了对helper实例的新引用后不能再变为null时才允许使用。

从高级角度来看,
volatile
保证了volatile写入之前发生的任何操作的结果(即,
new Helper()
)中的操作将在后续volatile读取后对任何其他线程可见(即,当另一个线程在外部检查中看到
Helper!=null

从低级角度来看,它取决于实现。但一般来说:

  • 应禁止使用以前的操作对易失性写入进行重新排序的编译器优化
  • JIT应该插入到生成的代码中,以防止在CPU级别进行类似的重新排序(如果特定的CPU体系结构允许这样的重新排序)

从高层角度来看,
volatile
保证在volatile写入之前发生的任何操作的结果(即
new Helper()
内的操作)在后续volatile读取之后(即,当另一个线程在外部检查中看到
Helper!=null
时)将对任何其他线程可见

从低级角度来看,它取决于实现。但一般来说:

  • 应禁止使用以前的操作对易失性写入进行重新排序的编译器优化
  • JIT应该插入到生成的代码中,以防止在CPU级别进行类似的重新排序(如果特定的CPU体系结构允许这样的重新排序)

没有volatile,因为如果(helper==null)
的初始
在同步块之外,则不存在可见性/一致性保证。特别是,
helper
可能不是null,而是指仅部分创建的对象

这是因为
helper=newhelper()
不是原子操作:

  • 它分配一些内存
  • 它构造对象
  • 它将对象的引用指定给
    helper
  • 如果没有同步,观察线程可以以任何顺序看到这些操作,特别是它可以看到2之前的3

    通过将
    helper
    设置为volatile,可以在写入和读取之间引入“发生在之前”关系(定义为),这确保如果从观察线程中看到3,也会看到1和2


    特别是,在volatile写入之前执行的任何操作都将从volatile读取中可见(当然是后续操作)。没有volatile,因为初始
    if(helper==null)
    在同步块之外,没有可见性/一致性保证。特别是,
    helper
    可能不为null,但引用了仅部分创建的对象

    这是因为
    helper=newhelper()
    不是原子操作:

  • 它分配一些内存
  • 它构造对象
  • 它将对象的引用指定给
    helper
  • 如果没有同步,观察线程可以以任何顺序看到这些操作,特别是它可以看到2之前的3

    通过将
    helper
    设置为volatile,可以在写入和读取之间引入“发生在之前”关系(定义为),这确保如果从观察线程中看到3,也会看到1和2


    特别是,在易失性写入之前执行的任何操作都将从易失性读取中可见(当然,如果是后续操作).

    您的意思是,在volatile write之前涉及volatile字段的任何操作对后续volatile read都是可见的吗?所有操作。在同一线程上的所有早期语句和write中都有一个before,在读取线程上的read语句和所有subqent语句之间也有一个before。因此,它的作用类似于m埃默里障碍影响