多线程案例-单例模式

单例模式是设计模式之一,能保证某个类在程序中只存在唯一一份实例,而不会创建出多个实例

单例模式的具体实现方法有很多,最常见的是 “饿汉”“懒汉” 两种。

饿汉模式

class Singlenton{
    private static Singlenton instance = new Singlenton();
    public static Singlenton getInstance(){
        return instance;
    }
    //在此类的外面无法调用构造方法,无法创建实例
    private Singlenton(){
        
    }
}

懒汉模式

类加载的时候不创建实例,第一次使用的时候才创建实例

单线程版

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

多线程版

相比单线程版,多线程版考虑了线程安全问题

线程安全问题发生在首次创建实例时,可能多个线程同时调用getInstance方法,就可能导致创建了多个实例。

加上 synchronized 可以改善线程安全问题

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

    }
}

多线程版优化

上面的代码虽然说解决了线程安全问题,但是只要调用了getInstance方法,就会触发加锁操作,产生阻塞,影响性能。

我们想要优化,就要在加锁之前判定一下是否需要加锁。

外层的if(instance==null)是判断实例有没有创建

内层的if(instance==null)进一步判断实例有没有创建,因为在外层 if 和加锁之间,切换了线程并创建了实例,此时切换到原来的线程如果没有判断,就会创建出多个实例。

但是光加了一个外层 if 还不够,此时可能因为指令重排序引起的线程安全问题

instance = new Singletonlazy();分为三条指令
  1. 分配内存空间
  2. 执行构造方法
  3. 内存空间的地址赋值给引用变量

编译器可能按照 1 2 3 的顺序来执行,也可能按照 1 3 2 的顺序执行

当按照 1 3 2的顺序执行时,由于 3 是把内存空间的地址赋值给引用变量,所以此时 instance现在不为 null 了,此时如果其他线程判断外层 if 时,由于instance不为null了,所以直接返回instance,但是此时instance指向没有初始化,上面值全是0的内存,此时getInstance到的就是个错误的值,会引发一系列不可预期的情况。

此时,我们用volatile 关键字告知编译器此变量指令不可重排序即可解决。

class Singletonlazy{
    private static volatile Singletonlazy instance = null;
    private static Object locker = new Object();
    public static Singletonlazy getInstance(){
        if(instance==null){
            synchronized (locker){
                if(instance==null){
                    instance = new Singletonlazy();
                }
            }
        }
        return instance;
    }
    private Singletonlazy(){

    }
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值