单例模式是我们在项目中最常用的模式,有很多种写法,在不同的应用场景中,不同的写法可能会产生不同的问题,在此做个整理记录。
简单单例模式的实现:a、将构造方法私有化;b、定义一个静态的私有变量来实例化类对象;c、对外提供一个静态的方法入口,返回已经实例化的类对象。
1、最初的单例写法:
public class SimpleSingleton {
private static SimpleSingleton singleton = new SimpleSingleton();
private SimpleSingleton(){
System.out.println("init.......");
}
public static SimpleSingleton getInstance(){
return singleton;
}
}
这种实现是线程安全的,多个线程进行访问时不会实例化多个对象,因为static属性只会被初始化一次,缺点是无论该实例是否用到都会被初始化,无形中增大了开销,为了解决这种浪费资源的问题,就有了下面的单例实现:
2、大家熟称的饿汉试实现:
public class SimpleSingleton {
private static SimpleSingleton singleton = null;
private SimpleSingleton(){
System.out.println("init.......");
}
public static SimpleSingleton getInstance(){
if(singleton==null){
singleton = new SimpleSingleton();
}
return singleton;
}
}
这种实现保证只有在调用该类的时候对象才被初始化,但是缺点是线程不安全,当多个线程同时访问的时候(多个线程同时访问并且判断为null),极可能实例化出多个对象,为了解决这种实例化多个对象的问题。继续优化getInstance()方法添加同步,但是这种虽然解决了线程安全问题,但是降低了性能。
3、double-cheched-locking模式
public class SimpleSingleton {
private volatile static SimpleSingleton singleton = null;
private SimpleSingleton(){
System.out.println("init.......");
}
public static SimpleSingleton getInstance(){
if(singleton==null){
synchronized (SimpleSingleton.class) {
if(singleton==null) {//防止两个线程同时经过第一个判断
singleton = new SimpleSingleton();
}
}
}
return singleton;
}
}
经过这么多的优化终于实现了线程安全又能实现懒加载的单例模式,其实还有一种个人比较喜欢,认为比较完美的,代码整洁的实现方式,使用内部类实现
4、完美的单例实现:
public class InnerClassSingleton {
private InnerClassSingleton(){
System.out.println("init.......");
}
public static class InnerClass{
public final static InnerClassSingleton instance = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance(){
return InnerClass.instance;
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,而这种方式是InnerClassSingleton类被装载了,instance不一定被初始化。因为InnerClass类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载InnerClass类,从而实例化instance。