class MyClass
{
private static volatile Resource resource;
public static Resource getInstance()
{
if(resource == null)
resource = new Resource();
return resource;
}
}
这里我怀疑是在实践中根据java并发性如果你使用易失性安全发布(即,一旦引用对另一个线程可见,数据也可用)。我可以在这里使用吗?但如果它是正确的,那么假设thread1现在检查“资源”并且它为null,因此它开始创建对象。当thread1正在创建objet时,另一个线程即thread2开始检查“resource”的值,而thread2发现它为null(假设创建“resource”对象需要相当长的时间,而且thread1尚未完成创建,所以安全发布没有发生因此不可用于thread2)那么它还会开始创建对象吗?如果是,那么类不变量就会中断。我对么?请帮助我理解这里特别使用volatile。
答案 0 :(得分:17)
你是对的,多个线程可以尝试创建一个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;
}
}
答案 1 :(得分:14)
volatile解决了一个可见性问题的问题。如果您要写入一个声明为volatile 的变量,则该值将立即显示给其他线程。众所周知,我们在os L1,L2,L3中有不同级别的缓存,如果我们在一个线程中写入变量,则不保证其他人可见,因此如果我们使用volatile,它会写入直接内存并且可见给别人但是volatile不能解决原子性的问题,即int a; a++;
不安全。因为有三个与之相关的机器指令。
答案 2 :(得分:1)
我认为,您应该在syncronized
定义之前使用getInstance
关键字。
为了获得更好的性能,您可以使用双重检查锁定模式:
答案 3 :(得分:0)
volatile
关键字保证读取和写入该变量是原子的。
根据tutorial
Reads and writes are atomic for all variables declared volatile
使用volatile变量可降低内存一致性的风险 错误,因为对volatile变量的任何写入都会建立一个 在与之后的相关读取之前发生 变量。这意味着始终对volatile变量进行更改 其他线程可见。更重要的是,这也意味着当a 线程读取一个volatile变量,它不仅看到最新的变化 挥发性,但也导致了代码的副作用 改变。
答案 4 :(得分:0)
当应用于字段时,Java volatile保证:
(在所有版本的Java中)读取都有全局排序 并写入一个volatile变量。这意味着每个线程 访问volatile字段将在之前读取其当前值 继续,而不是(可能)使用缓存值。 (然而, 无法保证volatile读取的相对顺序 并且使用常规读取和写入进行写入,这意味着它是 通常不是一个有用的线程构造。)
- 醇>
(在Java 5或更高版本中)易失性读写建立 发生在关系之前,就像获取和释放一样 互斥。
更多info。
答案 5 :(得分:0)
您是对的,在这种情况下,由于您描述的种族,资源可能会被构建两次。如果要在Java 5+中实现单例(没有显式锁定),请使用枚举单例,如What is an efficient way to implement a singleton pattern in Java?的答案中所述。
答案 6 :(得分:0)
首先,以这种方式使用Singleton,你实际上是在创建一个全局对象,这是一种不好的做法。我估计你会使用Enums。
答案 7 :(得分:0)
我建议添加volatile& amp;同步在一起。
注意:我们仍然需要仔细检查。
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;
}
}