您的位置:首页 > 其它

单例模式

2016-04-02 17:11 393 查看

1.单例模式定义

保证一个类仅有一个实例,并提供一个访问它的方法

2.UML建模图:



3.懒汉式

//等到要使用实例的时候才会创建
public class LazySingleton {
private static LazySingleton uniqueInstance = null;
private String data;

private LazySingleton(){
}

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

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}
}


4.饿汉式

//类加载的时候初始化
public class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton();
private String data;

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

//构造方法
private HungrySingleton(){
}

private static HungrySingleton getInstance(){
return hungrySingleton;
}

}


5.线程安全问题

饿汉式是线程安全的,在装载类的时候不会发生并发

懒汉式:

解决方法

1. public static synchronized Singleton getInstance(){} 在多线程环境下,效率很低。

2. 双重锁 Double Check Locking

volatile在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值

//volatile
private volatile static Singleton uniqueInstance = null;
private Singleton(){}
public static Singleton getInstance(){
if(uniqueInstance == null){
//同步块
synchronized(Singleton.class){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}


内部类

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

private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.instance;
}


枚举类

public enum Singleton{
uniqueInstancde;
public void singletonOperation(){}
}


6.真的只有一个对象么

其实,单例模式并不能保证实例的唯一性,只要我们想办法的话,还是可以打破这种唯一性的。以下几种方法都能实现。

1).使用反射,虽然构造器(newInstance)为非公开,但是在反射面前就不起作用了。

2).如果单例的类实现了cloneable,那么还是可以拷贝出多个实例的。

参考链接

3).Java中的对象序列化也有可能导致创建多个实例。避免使用readObject方法。因为通过序列化来生成对象时,无需调用构造器,读出的对象和写入的对象不相等(==)。这种单例的情况可以通过readResolve来解决,替换readObject读到的对象。

4).使用多个类加载器加载单例类,也会导致创建多个实例并存的问题。

7. 单例的扩展–只生成3个实例

/**
* 扩展单例模式,控制实际产生实例数目为 3 个
*/
public class ThreeSingleton {
//为后面使用的 key 定义一个前缀
private final static String DEFAULT_KEY = "cache";
//定义缓存实例的容器
private static Map<String,ThreeSingleton> map = new HashMap<>();
private static int number = 1;//定义初始化实例数目为 1
private final static int NUM_MAX = 3;

private ThreeSingleton(){

}

public static synchronized ThreeSingleton getInstance(){
//通过缓存理念及方式控制数量
String key = DEFAULT_PREKEY + number;
ThreeSingleton threeSingleton = map.get(key);
if(threeSingleton == null){
threeSingleton = new ThreeSingleton();
map.put(key, threeSingleton);
}
number++;//实例数目加 1
if(number > NUM_MAX){
number=1;
}
return threeSingleton;
}

public static void main(String args[]){
ThreeSingleton t1 = getInstance();
ThreeSingleton t2 = getInstance();
ThreeSingleton t3 = getInstance();
ThreeSingleton t4 = getInstance();
ThreeSingleton t5 = getInstance();
ThreeSingleton t6 = getInstance();
System.out.println(t1.toString());
System.out.println(t2.toString());
System.out.println(t3.toString());
System.out.println(t4.toString());
System.out.println(t5.toString());
System.out.println(t6.toString());
}
}


8. Java多线程(第六章)

如何使单例模式遇到多线程是安全的,正确的?

1. 立即加载(饿汉模式):在调用方法前,实例已经被创建

2. 延迟加载(懒汉模式):等到调用方法时,实例才被创建
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: