从线程角度看静态和易失性引用有什么区别? 例如,我想要一个单例对象,我的代码是这样的:
class Singleton {
Helper helper; /*Shall I make this variable static or volatile*/
Helper getHelper() {
if(helper==null) {
synchronized(this) {
if(helper==null) {
helper=new Helper();
}
}
}
return helper;
}
}
假设有两个线程访问getHelper()
方法。为避免多次创建Helper对象和脏读,我应该将引用设为static还是volatile?
任何人都可以解释一下线程缓存到图片中吗?
答案 0 :(得分:4)
对于这种延迟初始化,它需要是易失性的。
要使它成为单身人士,它必须是静态的。
所以你需要两个:)
有一个更简洁的模式可用于懒惰初始化静态单例,虽然它使用类加载器为你完成所有工作:
class Singleton {
private static class SingletonHolder {
private static final Singleton instance;
}
Singleton getInstance() {
return SingletonHolder.instance;
}
}
内部类仅在您第一次使用时加载,这意味着从外部类的角度来看它是延迟加载的。类加载器会为您处理所有同步。
答案 1 :(得分:1)
如果应用程序是多任务处理,则从Head First Design Patterns开始,您应该使用private volatile static
修改器。
易失性修饰符确保在多线程环境中正确处理该字段。没有它,仍然可能存在一种情况,即创建多个对象。
所以你的代码应该像
class Singleton {
private volatile static Helper helper;
public static Helper getInstance(){
if(helper==null) {
synchronized(this) {
if(helper==null){
helper=new Helper();
}
}
}
return helper;
}
}
答案 2 :(得分:0)
如果Helper是一个沉重的类,你只想拥有一个(在Singleton中)你应该让它静止。同步块内的实例化将阻止它导致问题。但是,Helper类中的任何非线程安全方法也应该适当地同步。