在java中使用volatile的单例

class MyClass { private static volatile Resource resource; public static Resource getInstance() { if(resource == null) resource = new Resource(); return resource; } } 

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

volatile解决了一个可见性问题 。 如果要写入一个声明为volatile的变量则该值将立即显示给其他线程。 众所周知,我们在os L1,L2,L3中有不同级别的缓存,如果我们在一个线程中写入变量,则不保证其他人可见,所以如果我们使用volatile,它会写入直接内存并且可见给别人 但是挥发性并不能解决primefaces性问题,即int a; a++; int a; a++; 不安全 AS有三个与之相关的机器指令。

你是对的,多个线程可以尝试创建一个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; } } 

我知道你不是在问更好的解决方案,但如果你正在寻找一个懒惰的单一解决方案,这绝对是值得的。

使用私有静态类来加载单例。 在调用之前不会加载类,因此在类之前不会加载引用。 通过实现加载类是线程安全的,并且你也需要很少的开销(如果你正在做重复的易失性负载[可能仍然很便宜],这个分辨率总是在初始构造后正常加载)。

 class MyClass { public static Resource getInstance() { return ResourceLoader.RESOURCE; } private static final class ResourceLoader { private static final Resource RESOURCE = new Resource(); } } 

我想,你应该在getInstance定义之前使用syncronized关键字。

为了获得更好的性能,您可以使用双重检查锁定模式:

  • IBM上的双重检查锁定和Singleton模式
  • 在Wiki上进行双重检查锁定

应用于字段时,Java volatile保证:

  1. (在所有版本的Java中)对volatile变量的读写都有一个全局排序。 这意味着访问volatile字段的每个线程将在继续之前读取其当前值,而不是(可能)使用缓存值。 (但是,无法保证常规读写的易失性读写的相对排序,这意味着它通常不是一个有用的线程构造。)

  2. (在Java 5或更高版本中)易失性读取和写入建立了先发生关系,就像获取和释放互斥锁一样。

更多信息

你是对的,在这种情况下,由于你描述的种族,资源可能会被构造两次。 如果要在Java 5+中实现单例(没有显式锁定),请使用枚举单例,如在Java中实现单例模式的有效方法的答案中所述? 。

volatile关键字保证对该变量的读写是primefaces的。

根据教程

 Reads and writes are atomic for all variables declared volatile 

使用volatile变量可以降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系。 这意味着对volatile变量的更改始终对其他线程可见。 更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用。

首先,以这种方式使用Singleton,你实际上是在创建一个全局对象,这是一种不好的做法。 我估计你用的是Enums。

这是我的建议,添加volatile和synchronized。

注意:我们还是要做双重检查。

 public class MySingleton { private static volatile MySingleton instance; private MySingleton() {} synchronized private static void newInstance() { if(instance == null) { instance = new MySingleton(); } } public static MySingleton get() { if(instance == null) { newInstance(); } return instance; } }