是否需要将synchronize关键字应用于实现单例模式的类的每个方法?
public class Singleton {
private Singleton(){}
public synchronized static Singleton getInstance()
{
if(instance == null)
instance = new Singleton ();
return instance;
}
public void DoA(){
}
}
由于Singletons不公开公共构造函数并且getInstance()方法是同步的,因此不需要同步方法DoA和Singleton类公开的任何其他公共方法。
这种推理是否正确?
答案 0 :(得分:19)
就像任何其他课程一样。它可能需要或可能不需要进一步同步。
考虑以下示例:
public class Singleton {
private Singleton() {}
public synchronized static Singleton getInstance() { ... }
private int counter = 0;
public void addToCounter(int val) {
counter += val;
}
}
如果要从多个线程使用该类,addToCounter()
具有竞争条件。解决这个问题的一种方法是使addToCounter()
同步:
public synchronized void addToCounter(int val) {
count += val;
}
还有其他方法可以修复竞争条件,例如使用AtomicInteger
:
private final AtomicInteger counter = new AtomicInteger(0);
public void addToCounter(int val) {
counter.addAndGet(val);
}
在这里,我们已经修复了竞争条件,而没有使用synchronized
。
答案 1 :(得分:10)
嗯,Singleton类的目的是它最多只有一个实例,所有Threads都可以访问同一个对象。
如果您不同步getInstance
方法,可能会发生以下情况
Thread1进入getInstance()
Thread2输入getInstance()
Thread1评估instance == null
到true
Thread2评估instance == null
到true
Thread1指定instance
并返回
Thread2 重新分配instance = new Singleton()
并返回。
现在线程都有Singleton类的不同实例,这是该模式应该阻止的。
同步可防止两个线程同时访问同一个代码块。因此,在实例化单例类时,在多线程环境中需要同步。
现在假设多个线程将同时尝试访问Singletons方法,同样可能需要同步这些方法。特别是如果他们改变数据而不是只读它,这是真的。
答案 2 :(得分:1)
使用Singleton的正确(实际上)方式
private static singleton getInstance() {
if (minstance == null) {
synchronized (singleton.class) {
if (minstance == null) {
minstance = new singleton();
}
}
}
return minstance;
}
答案 3 :(得分:1)
延迟初始化和线程安全解决方案:
public class Singleton {
public static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}