我在java中看到了一些例子,它们在代码块上进行同步以更改某些变量,而该变量最初被声明为易失性..我在单例类的示例中看到,他们将唯一实例声明为易失性,并且同步了初始化该实例的块......我的问题是为什么我们在同步时声明它是易失性的,为什么我们需要两者都做?其中之一不足以满足另一个吗?

public class someClass {
volatile static uniqueInstance = null;

public static someClass getInstance() {
        if(uniqueInstance == null) {
            synchronized(someClass.class) {
                if(uniqueInstance == null) {
                    uniqueInstance = new someClass();
                }
            }
        }
        return uniqueInstance;
    }

提前致谢。

有帮助吗?

解决方案

自身在这种情况下,如果第一个检查在同步块内(但它不是并且一个线程可能没有看到另一个线路,如果变量不易挥发,则一个线程可能没有看到更改)。单独挥发性是不够的,因为您需要原子执行多个操作。但要小心!你在这里拥有的是所谓的双重检查锁定 - 一个常见的成语,不幸的是不可能可靠地工作。我认为这已经改变了Java 1.6以来,但仍然可能存在风险。

编辑:当变量易于易变时,此代码自JDK 5(仅在我之前写的6)以来的工作原理正常工作,但它不会在JDK 1.4或更早版本下的预期工作。

其他提示

这使用了双重检查锁定,请注意 if(uniqueInstance == null) 不在同步部分内。

如果 uniqueInstance 不是易失性的,它可能是用部分构造的对象“初始化”的,其中除了在该对象中执行的线程之外,它的某些部分是不可见的 synchronized 堵塞。在这种情况下,易失性使得这是一个全有或全无的操作。

如果没有同步块,则最终可能会出现 2 个线程同时到达此点的情况。

if(uniqueInstance == null) {
      uniqueInstance = new someClass(); <---- here

然后你构造了 2 个 SomeClass 对象,这违背了目的。

严格来说,你不需要 volatile ,该方法可以是

public static someClass getInstance() {
    synchronized(FullDictionary.class) {
         if(uniqueInstance == null) {
             uniqueInstance = new someClass();
          }
         return uniqueInstance;
    }
}

但这会导致执行 getInstance() 的每个线程的同步和序列化。

这篇文章解释了这个想法挥发性背后。 它也被解决了在精英工作中, java同志在练习中

主要思想是,并发不仅涉及对共享状态的保护,而且还涉及线程之间该状态的可见性:这是valatile进出的地方。(这个较大的合同由 java memory model 。)

您可以在不使用同步块的情况下执行同步。 在其中使用volatile变量是必要的...... volatile更新主存储器的一个变量.AND 同步更新从主内存访问的所有共享变量。 所以你可以根据你的要求使用它..

我的两美分

FRIST快速解释了这个代码的直觉

if(uniqueInstance == null) {
        synchronized(someClass.class) {
            if(uniqueInstance == null) {
                uniqueInstance = new someClass();
            }
        }
    }
.

它检查的原因是OutceInstance== null两次是减少调用比较较慢的同步块的开销。所以被称为双重检查的锁定。

第二,它使用同步的原因易于理解,它使同步块原子内的两个操作。

持续的易失性修饰符确保所有线程都看到相同的副本,因此同步块外部的第一个检查将以“同步”的方式看到OutfleInstance的值 使用同步块。如果没有易失性修饰符,则一个线程可以将值分配给outformInstance,但另一个线程可能无法通过第一个检查看到它。(虽然第二个检查会看到它)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top