singleton design pattern offer 2 things:
one and only one instance of the class, and a global single point of access to that object
下面的例子用一个private的构造函数阻止了instance的生成,所以不能用new生成一个新的instance,只能用getInstance()来得到instance,可以看到生成instance后把它赋给static成员myInstance,所以可以always return the same object:
public class Logger{
//declare the constructor private to prevent clients from instantiating..
private Logger(){}
private static Logger myInstance;
//the static method to get instance..
public static Logger getInstance() {
if (myInstance == null) {
myInstance = new Logger();
}
return myInstance;
}
}
但是上面的实现有什么不妥之处?上面的实现对于单线程是有效的,但是对于多线程,仍然可以得到很多的object,违背了singleton的理念
对于多线程的singleton,看下面的例子
getInstance()方法中用到了synchronized修饰,每次只能一个线程访问,确保每次只能生成一个instance
public class Logger{
//declare the constructor private to prevent clients from instantiating..
private Logger(){}
private static Logger myInstance;
//the static method to get instance..
public static synchronized Logger getInstance() { //added..
if (myInstance == null) {
myInstance = new Logger();
}
return myInstance;
}
}
上面的实现有什么问题?poor performance。
其实本意是在第一次生成instance的时候用synchronized进行限制,但是整个method都变成了synchronized,导致多线程每次调用getInstance(), 这个地方会变成performance bottleneck
那么考虑把synchronized移到第一次生成instance的地方,是否就完美解决上述问题
public class Logger{
//declare the constructor private to prevent clients from instantiating..
private Logger(){}
private static Logger myInstance;
//the static method to get instance..
public static Logger getInstance() {
if (myInstance == null) {
synchronized (Logger.class) { //added..
myInstance = new Logger();
}
}
return myInstance;
}
}
仍然会有问题,如果两个线程同时第一次生成instance,同时判断到了myInstance== null
synchronized无法保护上面的判断,所以仍然会生成两个object
因此解决方法是实行双重检查myInstance== null, 但是这种方法不被推荐,因为erroneous out of order writes allowed by java memory model problem的关系, 虽然memory model已经修复了这个问题
public class Logger{
//declare the constructor private to prevent clients from instantiating..
private Logger(){}
private static Logger myInstance;
//the static method to get instance..
public static Logger getInstance() {
if (myInstance == null) {
synchronized (Logger.class) {
if (myInstance == null) { //added..
myInstance = new Logger();
}
}
}
return myInstance;
}
}
下面用另一种内部类的方法实现singleton
因为内部类are not loaded until they are referenced
仍然用private限制了构造函数
public class Logger{
//declare the constructor private to prevent clients from instantiating..
private Logger(){}
private static Logger myInstance;
public static class LoggerHolder {
public static Logger logger = new Logger();
}
public static Logger getInstance() {
return LoggerHolder.logger;
}
}