《Head-First-设计模式》笔记7-单例模式
更多请查看:Effective-Java-读书笔记03-用私有构造器或者枚举类型强化Singleton属性
定义
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
饿汉式方式
//饿汉式单例
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
饿汉式是线程安全的,因为虚拟机只会装载一次,在装载类的时候不会发生并发。
懒汉式方式
/**
* 利用双重加锁保证只在实例化变量的时候进行同步
*/
public class Singleton {
private static volatile Singleton instance; // 定义静态实例变量
private Singleton(){ }
/**
* 提供全局访问点
* @return 该类的实例
*/
public static Singleton getInstance(){
if(instance == null) { // 两次判空,可以只在第一次生成对象时进入同步块,提高效率
synchronized(Singleton.class) { // 进入同步块
if(instance == null) // 再次判空
instance = new Singleton();
}
}
return instance;
}
}
http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization
在成员变量 instance 前面加了一个 volatile
关键字,这个特别重要。在 Java 内存模型(JMM)中,并不限制处理器的指令顺序,说白了就是在不影响结果的情况下,顺序可能会被打乱。
在执行 instance = new Singleton(); 这条命令语句时,JMM 并不是一下就执行完毕的,即不是原子性,实质上这句命令分为三大部分:
- 为对象分配内存
- 执行构造方法语句,初始化实例对象
- 把sInstance的引用指向分配的内存空间
在 JMM 中这三个步骤中的 2 和 3 不一定是顺序执行的,如果线程 A 执行的顺序为 1、3、2,在第 2 步执行完毕的时候,恰好线程 B 执行第一次判空语句,则会直接返回 instance,那么此时获取到的 instance 仅仅只是不为 null,实质上没有初始化,这样的对象肯定是有问题的!
而 volatile 关键字的存在意义就是保证了执行命令不会被重排序,也就避免了这种异常情况的发生,所以这种获取单例的方法才是真正的安全可靠!
使用静态的内部类作为单例
public class Singleton {
//1 私有化构造函数,内部控制创建实例的个数
private Singleton(){}
//2 定义方法为客户端提供类实例
//3 需要定义成类方法,加static
public static Singleton getIntance(){
return SingletonInstace.instance;
}
//静态的内部类作为实例,一个类的静态属性只会在第一次加载类时初始化
private static class SingletonInstace{
static Singleton instance = new Singleton();
}
}
多个 class loader 环境下的单件模式
如果存在多个类加载器,多个类加载器可能同时加载我们的单件类,从而产生多个实例。
对于这种情况,我们可以显式指定使用哪一个 class loader 来加载单件类,这样就有效避免了上述问题。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com
文章标题:《Head-First-设计模式》笔记7-单例模式
文章字数:775
本文作者:Bin
发布时间:2018-07-08, 23:07:31
最后更新:2020-06-14, 22:42:50
原始链接:http://coolview.github.io/2018/07/08/Head-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E3%80%8AHead-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%8B%E7%AC%94%E8%AE%B07-%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。