Abh*_*kar 2 java singleton design-patterns
这是工作面试的问题。
实施单例模式。首先,不是存储一个实例,而是存储两个实例。在的每个偶数调用中
getInstance(),返回第一个实例,在的每个奇数调用中getInstance(),返回第二个实例。
我的实现如下:
public final class Singleton implements Cloneable, Serializable {
private static final long serialVersionUID = 42L;
private static Singleton evenInstance;
private static Singleton oddInstance;
private static AtomicInteger counter = new AtomicInteger(1);
private Singleton() {
// Safeguard against reflection
if (evenInstance != null || oddInstance != null) {
throw new RuntimeException("Use getInstance() instead");
}
}
public static Singleton getInstance() {
boolean even = counter.getAndIncrement() % 2 == 0;
// Make thread safe
if (even && evenInstance == null) {
synchronized (Singleton.class) {
if (evenInstance == null) {
evenInstance = new Singleton();
}
}
} else if (!even && oddInstance == null) {
synchronized (Singleton.class) {
if (oddInstance == null) {
oddInstance = new Singleton();
}
}
}
return even ? evenInstance : oddInstance;
}
// Make singleton from deserializaion
protected Singleton readResolve() {
return getInstance();
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Use getInstance() instead");
}
}
Run Code Online (Sandbox Code Playgroud)
看到问题了吗?可能会进入第一个调用getInstance,并且线程被抢占。然后,可以进入第二个呼叫,getInstance但会得到oddInstance而不是evenInstance。
显然,可以通过使其getInstance同步来防止此情况,但这是不必要的。在单例的生命周期中,只需要两次同步,而不是每个getInstance调用都需要同步。
有想法吗?
最重要的是,必须声明evenInstance和oddInstance变量volatile。请参阅著名的“双重检查锁定已损坏”声明:https : //www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
此外,对于偶数和奇数实例,您实际上应该在同步块中使用不同的对象,以便可以同时构造它们。
最终,Singleton构造函数中的check 被破坏,并且在第二次调用中将引发异常getInstance()
除此之外,还可以,但是如果您自己不进行并发工作,那就更好了:
public final class Singleton implements Cloneable, Serializable {
private static AtomicInteger counter = new AtomicInteger(1);
public static Singleton getInstance() {
if (counter.getAndIncrement() % 2 == 0) {
return EvenHelper.instance;
} else {
return OddHelper.instance;
}
}
private static class EvenHelper {
//not initialized until the class is used in getInstance()
static Singleton instance = new Singleton();
}
private static class OddHelper {
//not initialized until the class is used in getInstance()
static Singleton instance = new Singleton();
}
}
Run Code Online (Sandbox Code Playgroud)