欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例模式和双重检查锁定

程序员文章站 2022-05-17 18:53:54
...

相信大家对单例模式应该不陌生,每个人都能写出好多种单例模式的实现,总结来说就有五种:懒汉、饿汉、静态内部类、枚举和双重检查锁定。针对这几种方式的代码,可以在网上搜索到,这里就不再细说。
 
最近又看了一遍单例的几种实现方式,发现了一些其他东西。先看以下单例模式的实现代码
public class Singleton2 {

    private Singleton2(){}

    private static Singleton2 instance;

    public static synchronized Singleton2 getInstance() {
        if (instance == null) {
            instance new Singleton2();
        }
        return instance;
    }

}
这种实现方式利用了同步的方式保证线程安全,但是效率特别低下,同步锁要善用。
 
为了提高效率,可以把同步锁放到方法里,先判断instance是否为空,若不为空加锁进行初始化,若为空就可以直接获取对象,这样可以减少一大部分的线程等待,代码如下:
public class Singleton7 {

    private Singleton7(){}
 
    private static Singleton7 instance;

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

}
 
现在提个问题,以上代码真的正确吗?觉得代码没问题的人,可以继续往下看,能看出问题的,估计下面的东西也知道。
 
这里先把问题点明,以上代码中这一行private static Singleton7 instance;是有问题的,缺少了修饰符volatile,这个可是很重要的。
 
这里先说明类初始化大概的流程:
1、分配内存空间
2、初始化对象
3、设置instance指向分配的内存地址
但是在这三步中,第二步和第三步是可以调换顺序的,也即
1、分配内存空间
3、设置instance指向分配的内存地址
2、初始化对象
 
基于上面的理论,以上代码在缺少volatile的情况下,会有以下问题

单例模式和双重检查锁定
            
    
    博客分类: 原创笔记java 双重检查锁定单例模式同步锁类加载
 
从图中大致能看出B线程虽然获取到了instance对象,但这个对象其实没有真正初始化。
 
知道这个问题之后,volatitle在这里就能起到至关重要的作用了,使用了volatitle之后,在JDK1.5之后,类初始化流程中第二步和第三步在多线程的情况会被禁止,从而保证代码的正常执行。 
  • 单例模式和双重检查锁定
            
    
    博客分类: 原创笔记java 双重检查锁定单例模式同步锁类加载
  • 大小: 102.9 KB