您的位置:首页 > 编程语言 > Java开发

Java设计模式之单例模式

2016-06-25 23:38 543 查看

Java设计模式之单例模式

1、定义:确保一个类只有一个实例,并提供一个全局的访问点

2、关键点:

- 构造函数不对外开放,一般为private

- 通过一个静态方法或者枚举返回单例类对象

- 确保单例类的对象只有一个,尤其是在多线程环境下

- 确保单列类在反序列化的时候不会构建新的对象

3、常见写法:

简单模式

public class Singleton{
private static final Singleton mInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return mInstance;
}
}


简单模式在类加载时就把实例初始化完成了,当需要调用此实例的时候,直接返回mInstance。

懒汉模式

public class Singleton{
private static final Singleton mInstance;
private Singleton(){}
public static synchronized Singleton getInstance() {
if(mInstance == null) {
mInstance = new Singleton();
}
return mInstance;
}
}


懒汉模式就是延迟类的初始化到需要的时候,当调用getInstance的时候才会真正的初始化该类。为了防止在多线程环境中产生多个实例,需要在getInstance方法上添加同步关键字synchronized。但是频繁使用synchronized会增加性能消耗。

双重检查锁方式

public class Singleton{
private static final volatile Singleton mInstance;
private Singleton(){}
public static Singleton getInstance() {
if(mInstance == null) {
synchronized(Singleton.class) {
if(mInstance == null) {
mInstance = new Singleton();
}
}
}
return mInstance;
}
}


双重检查锁方式既延迟初始化又避免了不必要的同步,但是由于构建实例并不是原子操作,所以在复杂的多线程环境下,仍有可能产生多个实例或者实例初始化错误的情况发生(尽管概率很低),所以我们在全局变量mInstance前面增加了volatile关键字,保证了mInstance对象每次都是从主内存中读取。

更优雅的写法-内部静态类

public class Singleton{
private Singleton() {
}

private static class SingletonHolder{
private static final Singleton mInstance = new Singleton();
}

public static Singleton getInstance() {
return SingletonHoldler.mInstance;
}
}


延迟初始化,因为只有当调用getInstance方法的时候才会导致虚拟机加载SingletonHolder类。

确保线程安全并保证单例对象的唯一性,因为一个类只有可能被加载一次。

注意:上述写法在绝大多数情况下是可能保证单例对象唯一性的,但有一种情况除外—–反序列化。通过序列化可以将一个对象写到磁盘上,然后再读取回来。即使构造函数是私有的,反序列化依然可以通过特殊途径去创建类的一个新的实例。解决方法就是在类中添加readResolve()方法,它是一个钩子函数,可以让开发人员控制对象的反序列化。

private Object readResolve() throws ObjectStreamException {
return instance;
}


枚举单例

public enum SingletonEnum {
INSTANCE;
public void doSomething() {

}
}


枚举单例的方式是最简单的,也是最安全的(默认枚举实例的创建时线程安全的),并且没有序列化和反序列化的问题。

基于容器实现的单例

public class SingletonManager {
private static final Map<String, Object> objMap = new HashMap();
private SingletonManager(){}

static {
//类初始化时将多个单例注入到这个管理类中
registerService(key1, instance1);
...
}

public static void registerService(String key, Object instance) {
objMap.put(key, instance);
}

public static Object getService(String key) {
return objMap.get(key);
}
}


使用容器类存储单例,可以管理多种单例,并且在使用时通过统一的接口进行获取操作,降低用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息