Java单例模式的几种写法

写过很多单例模式实现,今天贴一个书中的写法。
单例模式定义:一种设计模式,在只需要为类创建一个实例的时候使用。
要求:只能有一种创建实例的方式,同时不能获得处于未初始化状态的对象引用。
因此在单例模式中,需要有一个声明为private的构造方法,而且只调用一次。

package oop;

/** * 单例模式 * * @author lunatictwo */
public class Singleton {

    private final static Singleton instance = new Singleton();
    private static boolean isInit = false;

    // 构造方法,只在初始化instance时才调用构造方法
    private Singleton() {
        super();
    }

    private void init() {
        // 初始化方法放在私有方法中
    }

    // 通过静态辅助方法获得实例
    public static synchronized Singleton getInstance() {
        if (isInit) {
            return instance;// 判断是否激活
        }
        instance.init();// 激活实例,并保存状态为已激活,下次请求创建实例时不会再次初始化
        isInit = true;
        return instance;
    }

}

此时在获取单例实例的时候,只能通过getInstance() 获取。

更新:(2016-01-23):今天再加几个别的写法,免得混淆视听。

上边写的单例属于饿汉模式的同步安全写法,就是每次在使用对象之前就给它初始化,保证对象不会饿死…现在贴个懒汉模式的单例:

package oop;

/** * LazySingleton * * @author lunatictwo * */
public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton() {
        super();
    }

    public static LazySingleton getInstance() {
        if (null == instance) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

如果觉得线程不安全,就加个同步锁:

package oop;

/** * LazySingleton * * @author lunatictwo * */
public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton() {
        super();
    }

    public static synchronized LazySingleton getInstance() {// 加同步锁
        if (null == instance) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

同时为了提高效率,还可以只在创建对象的时候加锁同步(双重检查),但是这个模式存在如下:

package oop;

/** * DoubleCheckSingleton * * @author lunatictwo * */
public class DoubleCheckSingleton {
    private static DoubleCheckSingleton instance = null;

    private DoubleCheckSingleton() {
        super();
    }

    public static synchronized DoubleCheckSingleton getInstance() {
        if (null == instance) {
            synchronized (DoubleCheckSingleton.class) {
                if (null == instance) {
                    instance = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

但是这个写法存在隐患,当两个线程去初始化对象实例的时候,由于初始化对象需要时间,第一个线程创建了对象地址后(并没有完全创建完毕时),第二个线程判断该对象已经存在,所以直接返回一个对象实例,可是对于第二个线程来说该对象实例是没有完全初始化的。所以不推荐这种写法。

其实最好的写法是使用内部类,既可以做到线程安全,写法也很简单,如下:

package oop;

/** * InternalClassSingleton * * @author lunatictwo * */
public class InternalClassSingleton {
    private static class InternalClassSingletonHandler {
        public final static InternalClassSingleton instance = new InternalClassSingleton();
    }

    public static InternalClassSingleton getInstance() {
        return InternalClassSingletonHandler.instance;
    }

}

你可能感兴趣的:(java)