设计模式之双锁校验单例模式的理解

单例模式对于广大开发者来说都不陌生了,单例模式也分为饿汉模式,懒汉模式,本文主要讲解的是volitale+synchronized修饰的单例模式来保证并发情况下的系统安全.

首先介绍下以前用的单例模式

1:不加锁的单例模式

1.1:懒汉单例模式

懒汉:顾名思义就是比较懒,只有需要的时候才会创建这个对象.

public class Singleton{
    private static Singleton singleton=new Singleton();
    private Singleton(){

    }
    public static Singleton getSingleton(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }
}

1.2:饿汉单例模式

饿汉:就像看见喷香的肉一样激动.不管食物有没有毒,先吃了再说. 对于编程来说不管有没有对象,先创建了再说.

public class Singleton{
    private static Singleton singleton=new Singleton();
    private    Singleton(){

    }
    public static Singleton getSingleton(){
      
        return singleton;
    }
}

1.3:两者的对比与不足之处

懒汉单例:代码实现简单,但没有加synchronized锁,线程不安全,在并发情况下不能正常运行。

饿汉单例:线程安全,没有加锁,执行效率会提高。在类加载时就初始化,会造成内存浪费。

 

2:volatile+synchronized的双锁校验单例模式

ublic class Singleton{
//采用volatile关键字来保证并发线程下的指令重排
    private static volatile Singleton singleton;
    private    Singleton(){
    }
    public static Singleton getSingleton(){
        if(singleton==null){
//采用synchronized来进行加锁
            synchronized(Singleton.class){
                if(singleton==null){
                    singleton=new Singleton();
                }
            }
        }
        return singleton;
    }
}

这种方式采用双锁机制,安全且在多线程情况下能保持高性能。可以看到这个单例模式多了一个volatile和synchronized关键字来保证并发情况下的安全。那么问题来了,为什么这两个关键字就能保证并发的安全呢。下面讲解一下这两个介绍一下这两个关键字的作用。

2.1:volatile的特性

volatile是java中的关键字可以用来修饰变量。它可以保证变量的可见性以及防止指令重排。

可见性就是指一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(

禁止进行指令重排序就要从创建对象的过程来说起了。

创建一个对象可以分三个步骤:

1.分配内存对象空间

2.初始化对象

3.设置instance指向刚分配的内存地址,此时instance != null

2和3不存在数据依赖关系,而且无论重排前还是重排后程序的执行结果在单线程中并没有改变,因此这种重排优化是允许的。但是在多线程的情况下2和3的顺序就会颠倒。这个时候对象还没有初始化完成,就返回了,所以会有安全问题。而volatile能防止这种情况发生。

2.2:synchronized的特性

synchronized是java中常见的锁关键字,在jdk1.6以后进行了大量优化,大幅提高了执行效率。

这个关键字内容较多,后续会专门进行介绍,目前只介绍单例模式中这个关键字的作用。

synchronized修饰的代码有几种:

修饰一个类:其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象;

修饰一个方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

修饰一个静态的方法:其作用的范围是整个方法,作用的对象是这个类的所有对象;

修饰一个代码块:被修饰的代码块称为同步语句块,其作用范围是大括号{}括起来的代码块,作用的对象是调用这个代码块的对象;
而在本单例中代码为   synchronized(Singleton.class){}  这一行。锁住了这个类所对应的对象,就实现了全局锁的效果。这个时候安全的单例模式就明白了。

 

本文主要是从我个人的理解角度来进行解释。思考不合理或者有问题的地方,欢迎指正.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值