在 java 中具有易失性的单例

2022-09-03 09:03:43
class MyClass
{
      private static volatile Resource resource;

      public static Resource getInstance()
      {
            if(resource == null)
                  resource = new Resource();
            return resource;
      }
 }

在这里,我怀疑根据java并发性在实践中,如果你使用易失性,安全的发布发生(即一旦引用对另一个线程可见,数据也是可用的)。那么我可以在这里使用它吗?但是如果它是正确的,那么假设 thread1 现在检查“resource”并且它是 null,所以它开始创建对象。当 thread1 创建 objet 时,另一个线程即 thread2 出现并开始检查“resource”的值,thread2 发现它为 null(假设创建 “resource” 对象需要相当长的时间,并且由于 thread1 尚未完成创建,因此安全发布尚未发生,因此 thread2 不可用)那么它也会开始创建对象吗?如果是,则类不变中断。我说的对吗?请帮助我理解这里挥发性的这种特殊用途。


答案 1

您是对的,多个线程可能会尝试创建一个 Resource 对象。Volatile 只保证如果一个线程更新引用,所有其他线程将看到新的引用,而不是某些缓存的引用。这更慢,但更安全。

如果只需要一个延迟加载的资源,则需要执行如下操作:

class MyClass
{
      private static volatile Resource resource;
      private static final Object LOCK = new Object();

      public static Resource getInstance()
      {
            if(resource == null) { 
                synchronized(LOCK) { // Add a synch block
                    if(resource == null) { // verify some other synch block didn't
                                           // write a resource yet...
                        resource = new Resource();
                    }
                }
            }
            return resource;
      }
 }

答案 2

易失性解决了一个问题,即 可见性问题 。如果要写入一个声明为易失性的变量,则该值将立即对其他线程可见。众所周知,我们在os L1,L2,L3中具有不同级别的缓存,如果我们写入一个线程中的变量,则不能保证它对其他线程可见,因此如果我们使用易失性,它会写入引导内存并对其他人可见。但易失性并不能解决原子性问题,即 不安全。由于有三个机器指令与之相关。int a; a++;


推荐