单例模式几种安全的实现
单例的应用场景:
需要频繁的创建和销毁对象的、创建对象时耗时过多或者消耗资源过多但是又经常用到的对象、工具类对象或数据库或文件的对象。
当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则用多例。
一、懒汉式,线程安全的实现
public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }
这虽然是线程安全的,但是效率低。还有一些比较常犯的错误,不加同步限制的,不做举例。
二、饿汉式,线程安全
1.构造器私有化
2.类的内部创建对象
3.像外部暴露一个静态的公共方法。getInstance
优点:在类装载的时候就完成了实例化。避免了线程同步问题。
缺点:没有达到Lazy Loading(懒加载)的效果,如果从来没使用过这个类,就会造成内存的浪费。
public class Singleton{
//类加载时就初始化
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
但是要是明确要求是需要懒加载的,这个就不行的
第二种写法,在类的静态代码块中创建实例:
public class Singleton { //1.构造函数私有化 private Singleton() { } //2.在本类的内部创建对象实例 private static Singleton instance; static { instance = new Singleton(); } //3.提供静态方法,返回实例对象 public static Singleton getInstance() { return instance; } }
三、静态内部类
我比较倾向于使用静态内部类的方法,这种方法也是《Effective Java》上所推荐的。
public class Singleton {
|
四、枚举
用枚举写单例实在太简单了!这也是它最大的优点。下面这段代码就是声明枚举实例的通常做法。
public enum EasySingleton{
|
创建enum时,编译器会自动为我们生成一个继承自java.lang.Enum的类,我们上面的enum可以简单看作:
class Type extends Enum{ public static final Type A; public static final Type B; ... }
demo:
public enum SingleEnum { INSTANCE; private static String[] strings = {"1", "2"}; public String[] getStrings() { return strings; } }
五、双重检测
//双重检查 public class Singleton {
private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
这个代码只在第一次,两个线程不能同时执行synchronized方法,但是,后面install不为空后,instance == null就直接pass掉了。volatile的作用理解是instance = new Singleton立即到内存中生效。