单例模式是一种常用的设计模式。在JVM中,该模式能够保证该对象只有一个实例存在。
好处:
1.某些类创建频繁,对于大型系统是很大一笔开销。
2.某些类只允许一个对象存在,相同的对象多于一个会引起系统混乱。
3.去掉new,降低内存使用频率,减轻GC压力。
往往很多时候用到单例模式会简简单单写几行类似于如下的代码了事:
public class Singleton {
private static Singleton singleton = null;
private Singleton() {//私有构造方法,防止该类被实例化。
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
但是,这样的写法在多线程下显然是不行的。于是有了下面的代码:
public class Singleton {
private static Singleton singleton = null;
private Singleton() {//私有构造方法,防止该类被实例化。
}
public synchronized static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
但synchronized锁住的其实是该对象,在每次getInstance的时候,该对象都会被锁住。因此,开销还是蛮大的。
如果把synchronized放入方法内部:
public class Singleton {
private static Singleton singleton = null;
private Singleton() {//私有构造方法,防止该类被实例化。
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (singleton){
singleton = new Singleton();
}
}
return singleton;
}
}
则开销会小很多。仅仅是在需要创建对象的时候才加锁。
不过,问题还是出现了:
JVM在创建一个对象和赋值的时候是有可能分开进行的。也就是说,A对象最先进入了同步锁,离开的时候对象Singleton的空间已经创建好并给了singleton,但是该空间里的实例还没有实例化。
而此时,B对象发现singleton已经不为null,而直接去使用了singleton,由于实例化尚未完成,造成错误。
事实上,单例模式是使用内部类完成线程互斥维护单例的。JVM能够保证当一个类在加载的时候,该类是保持线程互斥的。在调用getInstance方法时,静态类SingletonFactory会被加载,同时完成线程安全的 new Singleton,并一次初始化完毕。而该实例化仅仅在第一次的时候完成,从而保证了性能上不会重复进行,也无需在什么方法上套用synchronized。
线程安全而且效率不低。
public class Singleton {
private Singleton() {//私有构造方法,防止该类被实例化。
}
public static class SingletonFactory{
public static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonFactory.instance;
}
}
也就是说,我们是用了个静态类代替了静态方法。
原文地址:http://blog.csdn.net/langduhualangdu/article/details/44132445