单例模式

单例模式属于创建型模式。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类频繁地创建与销毁。何时使用:当您想控制实例数目,节省系统资源的时候。

特点: ① 单例类只能有一个实例。
      ② 单例类必须自己自己创建自己的唯一实例。
      ③ 单例类必须给所有其他对象提供这一实例。

要点:① 私有的构造方法。② 指向自己实例的私有静态引用。③ 以自己实例为返回值的静态的公有的方法。

优点:①在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 

   ②避免对资源的多重占用(比如写文件操作)。 ③可以全局访问。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

UML图:

单例模式有很多种写法,具体代码如下:

1. 懒汉式(最简单版本):

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

这种实现最简单,但是非线程安全。

 

2. 懒汉式(synchronized版本):

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

比第一种实现好在线程安全。但这种方法也有问题,就是会强制除进入方法的线程外的其他线程等待,会降低程序的执行效率。

 

3. 懒汉式(双重检查版本):

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

这种方法双重检查(Double-Check)。第一个if (instance==null)其实是为了解决第2种方法的效率问题,只有instance为null的时候才进入synchronized的代码段;第二个if (instance==null)则是跟第2种方法一样是为了防止可能出现多个实例的情况。

这种方法还是会出现问题,主要是由于instance=new Singleton()这句不是一个原子操作,JVM指令重排会导致问题。

事实上在 JVM 中这句话大概做了下面 3 件事情。
① 给 singleton 分配内存
② 调用 Singleton 的构造函数来初始化成员变量,形成实例
③ 将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null 了)
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。总结来说就是线程T1对instance的写操作没有完成,线程T2就执行了读操作。

 

4. 懒汉式(终极版本):

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;
   }
}

这种方法跟第3种方法的区别就在于将instance声明为volatile,保证不会出现指令重排,这样在按顺序执行完1-2-3之前不会出现另外一个线程调用读操作。

 

5. 饿汉式(最简单版本):

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

最简单,线程安全;但可能由于初始化得太早造成资源的浪费。

 

6. 静态内部类实现

public class Singleton {  
    private static class SingletonHolder {  
    	private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton () {}  
    public static final Singleton getInstance() {  
    	return SingletonHolder.INSTANCE;  
    }  
}

 

7. 枚举实现

public class SingletonExample {

    // 私有构造函数
    private SingletonExample() {

    }

    public static SingletonExample getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    private enum Singleton {
        INSTANCE;

        private SingletonExample singleton;

        // JVM保证这个方法绝对只调用一次
        Singleton() {
            singleton = new SingletonExample();
        }

        public SingletonExample getInstance() {
            return singleton;
        }
    }
}

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值