网上总结挺多的,有一个是7种的,其实有几种设计的不太合理,有漏洞,所以怎样设计单例模式也需要具体情况具体分析
我就写几种做个参考吧:
第一种懒汉式:
package singletonpattern;
public class LazySingleton {
private static LazySingleton singleton;
private LazySingleton() {
super();
}
public static LazySingleton getInstance() {
if (singleton == null) {//这里如果在第一个线程判断完毕之后进入代码块里,另一个线程获得CPU执行权,也到这来判断,此时判断完的线程停止且未创建对象,这就导致了当前线程会认为没有实例,两个对象就这样被创建了
singleton = new LazySingleton();
}
return singleton;
}
}
这种缺陷很大,多线程的请求会导致不仅仅有一个实例产生。
第二种线程安全懒汉式:
package singletonpattern;
public class LazySingleton {
private static LazySingleton singleton;
private LazySingleton() {
super();
}
public synchronized static LazySingleton getInstance() {
if (singleton == null) {
singleton = new LazySingleton();
}
return singleton;
}
}
区别就在于用了synchronized关键字,保证了同步,但是这样极大地降低了效率,特别是锁住的这个方法里执行需要较长时间
所有的线程都要等待,太差了。
第三种饿汉式:
package singletonpattern;
public class HungrySingleton {
private static HungrySingleton singleton = new HungrySingleton();
private HungrySingleton() {}
public synchronized static HungrySingleton getInstance() {
return singleton;
}
}
说他饿汉主要是因为他没等别人调用方法就直接new了这个实例,这个倒是不算错,可是有些时候某些实例不需要那么早被创建出来或者很耗费资源之类的只有需要才需要被创建出来,这种方式失去了延迟加载的能力,不爽!
第四种静态内部类的形式:(这个方式参考别人的)
public class SingletonDemo5 {
private static class SingletonHolder{
private static final SingletonDemo5 instance = new SingletonDemo5();
}
private SingletonDemo5(){}
public static final SingletonDemo5 getInsatance(){
return SingletonHolder.instance;
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种方式不同的是(很细微的差别):第三种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三种方法就显得更合理。
第五种双重校验锁:
package singletonpattern;
public class DobleLockSingleton {
private volatile static DobleLockSingleton singleton;
//volatile 确保当uniqueInstance初始化为Singleton的实例时,多个线程可以正确的处理uniqueInstance变量。
private DobleLockSingleton() {
}
public static DobleLockSingleton getInstance() {
if (singleton == null) {//这其实是第二种方式的进阶版,这里尚且存在多线程问题
synchronized (DobleLockSingleton.class) {
//只有第一次才会执行这里面的代码。也就是说第一次为同步,后来就进不来这个判断里了。
if (singleton == null) {
singleton = new DobleLockSingleton();
}
}
}
return singleton;
}
}