class MyClass
{
private static volatile Resource resource;
public static Resource getInstance()
{
if(resource == null)
resource = new Resource();
return resource;
}
}
Run Code Online (Sandbox Code Playgroud)
这里我怀疑是在实践中根据java并发性,如果你使用volatile,安全发布会发生(即一旦引用对另一个线程可见,数据也可用).我可以在这里使用吗?但如果它是正确的,那么假设thread1现在检查"资源"并且它为null,因此它开始创建对象.当thread1正在创建objet时,另一个线程即thread2开始检查"resource"的值,而thread2发现它为null(假设创建"resource"对象需要相当长的时间,而且thread1尚未完成创建,所以安全发布没有发生因此不可用于thread2)那么它还会开始创建对象吗?如果是,那么类不变量就会中断.我对么?请帮我理解这里特别使用的volatile.
cor*_*iKa 18
你是对的,多个线程可以尝试创建一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 14
volatile解决了一个可见性问题.如果要写入一个声明为volatile的变量,则该值将立即显示给其他线程.众所周知,我们在os L1,L2,L3中有不同级别的缓存,如果我们在一个线程中写入变量,则不保证其他人可见,因此如果我们使用volatile,它会写入直接内存并且可见给别人 但挥发性并不能解决原子性问题,即int a; a++;不安全.因为有三个与之相关的机器指令.
我知道你不是在问更好的解决方案,但如果你正在寻找一个懒惰的单一解决方案,这绝对是值得的.
使用私有静态类来加载单例.在调用之前不会加载类,因此在类之前不会加载引用.通过实现加载类是线程安全的,你也可以产生很少的开销(如果你正在做重复的易失性负载[可能仍然很便宜],这个分辨率总是在初始构造后正常加载).
class MyClass {
public static Resource getInstance() {
return ResourceLoader.RESOURCE;
}
private static final class ResourceLoader {
private static final Resource RESOURCE = new Resource();
}
}
Run Code Online (Sandbox Code Playgroud)