一天一个设计模式——(Singleton)单例模式(线程安全性)
2020-12-13 03:45
标签:它的 不用 编译器 延迟加载 int 有序性 设计 方法 检查 一、模式说明 有时候,我们希望在应用程序中,仅生成某个类的一个实例,这时候需要用到单例模式。 二、模式类图 三、模式中的角色 四、代码示例 单例模式比较简单,要实现单例模式只需保证三点: 测试类运行结果如下: 上面的代码中,Singleton类的方法和成员属性都是静态的,原因是我们不能直接创建Singleton类的实例,但是想通过类的方法调用获取实例,因此方法必须是静态的,同时,静态方法只能操作静态成员,所以对象也是静态的。 另外注意到,Singleton类的构造函数被设置为私有的,这样可以避免通过调用new方法来直接创建对象。 五、扩展——几种不同模式的单例模式实现及其线程安全性分析 上面的代码示例中实现的单例模式被称为“饿汉模式”,因为类在加载的过程中,单例就已经初始化完成,确保在获取Instance的时候,实例是已经存在的了。因此饿汉模式是线程安全的单例模式实现,可以直接用于多线程环境。并且由于是在类的加载阶段就生成了实例,因此第一次调用获取对象方法时效率高。缺点是:无论程序最终是否会用到这个类,这个类都会被创建,会占用一定的内存。 与饿汉模式相对的,如果我们在加载类的时候不创建实例,等到第一次调用getInstance方法时才生成实例对象,这种做法就是“懒汉模式”。 懒汉模式相比于饿汉模式,由于是在第一次调用getInstance方法时才通过构造函数创建对象,如果对象的创建代码比较复杂,会影响第一次获取对象的效率。同时,懒汉模式如果不做特殊处理,很明显是线程不安全的,如果要使用懒汉模式又想用在多线程环境中,有几种方式实现线程安全: 1、第一个能想到的方法就是加锁。 这种写法的最大缺点就是效率低!每个线程在想获得类的实例调用getInstance()方法都要进行同步,实际上这个方法只执行一次实例化代码就够了,后面每次获取实例直接return就行了,不用每次都让方法同步。 2、第二个方法:双重校验锁 这种写法通过两次判断lazySingletonDoubleCheck成员是否为空,从而决定是否创建实例,一旦实例创建后,后续调用获取对象的方法时,直接返回对象,优点:线程安全、延迟加载、高效。 这里必须要插播一下volatile这个java关键字:volatile关键字用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效。volatile具备可见性和有序性,不具备原子性。 3、第三种写法:静态内部类 这种写法比较推荐,这种方式看上去像是饿汉模式,实际上有区别,由于静态内部类的特性,在外部类加载时并不会马上实例化,只有在调用getInstance方法时,才会实例化类。这里,JVM帮助我们保证了线程安全性,当JVM进行类的初始化时,其他线程是无法进入的。保证了线程安全、延迟加载,效率高。 4、第四种写法:利用枚举类(实现单例模式的最佳做法) 创建一个对象的方式有多种:new,克隆,序列化,反射。前三种情况,上面的饿汉模式和线程安全的懒汉模式都可以保证生成实例的唯一性,但是对于最后一种——反射,无法保证实例的唯一性:通过反射可以获取到类的构造方法(即使声明构造方法是private的也没用,反射可以打破一切封装,但是枚举例外) 可以使用SingletonEnum.INSTANCE方式获取枚举的实例。由于枚举的构造方式和单例模式很像(构造方法私有化),而且不用考虑序列化等问题。因此使用枚举来构建单例模式是目前最好的做法,并且不被反射打破。(可以参考阅读《Effective Java》) 六、相关的模式 一天一个设计模式——(Singleton)单例模式(线程安全性) 标签:它的 不用 编译器 延迟加载 int 有序性 设计 方法 检查 原文地址:https://www.cnblogs.com/zheng-hong-bo/p/11087301.html
package com.designpattern.cn.singletonpattern;
public class Singleton {
private static Singleton singleton = new Singleton();
//也可以使用静态域,在类加载时创建实例
//static {singleton = new Singleton();}
private Singleton(){
System.out.println("Instance created!");
}
public static Singleton getInstance(){
return singleton;
}
}
package com.designpattern.cn.singletonpattern;
public class LazySingletonThreadLock {
private static LazySingletonThreadLock lazySingletonThreadLock = null;
private LazySingletonThreadLock(){};
public static synchronized LazySingletonThreadLock getInstance(){
if(lazySingletonThreadLock == null){
lazySingletonThreadLock = new LazySingletonThreadLock();
}
return lazySingletonThreadLock;
}
}
package com.designpattern.cn.singletonpattern;
public class LazySingletonDoubleCheck {
//双重检查方式
private static volatile LazySingletonDoubleCheck lazySingletonDoubleCheck = null;
private LazySingletonDoubleCheck(){}
public static LazySingletonDoubleCheck getInstance(){
if(lazySingletonDoubleCheck == null){
synchronized (LazySingletonDoubleCheck.class){
if(lazySingletonDoubleCheck == null){
lazySingletonDoubleCheck = new LazySingletonDoubleCheck();
}
}
}
return lazySingletonDoubleCheck;
}
}
package com.designpattern.cn.singletonpattern;
public class LazySingletonStaticInnerClass {
private LazySingletonStaticInnerClass(){}
//静态内部类
private static class singletonInstance{
private static final LazySingletonStaticInnerClass INSTANCE = new LazySingletonStaticInnerClass();
}
public static LazySingletonStaticInnerClass getInstance(){
return singletonInstance.INSTANCE;
}
}
package com.designpattern.cn.singletonpattern;
public enum SingletonEnum {
INSTANCE;
}
文章标题:一天一个设计模式——(Singleton)单例模式(线程安全性)
文章链接:http://soscw.com/essay/28216.html