EffectiveJava-强化懒汉单例(图示看懂为什么懒汉会线程不安全)

何为单例

概念:某个类中只存在一个实例,且只提供一个全局访问点
场景:很多时候一些类不需要重复创建,比如配置、工具类等
与静态方法区分:静态方法也符合上述描述,某个类不需要重复创建。他和单例模式性能相差不大。其最主要的区别就是面向对象思想的区分,静态方法没有继承等概念。所以如果一个方法如果与实例无关,那么他就是静态的。

单例区分

单例分为懒汉和饿汉。
懒汉只有在使用的时候才会生成对象,所以效率更好一点。
但利弊总是共存的,在使用懒汉的时候就要保证线程安全。

最简单的懒汉:

public class Test {

    private Test() {

    }

    private Integer age;

    private static Test instance;

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

获取实例的时候先判断是否存在,如果不存在那么实例化一个单例。

问题

但是如果多线程访问此方法就会有问题
多线程会出现多个实例
所以为了解决线程不安全的问题可以有两种解决方法
1、直接在方法上加锁
2、使用双重校验锁

解决方案

方案一:方法加锁

直接在获取实例方法上面加锁

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

缺点:每次获取实例都要加锁,效率不行

方案二:双重校验锁

仅在第一次初始化的时候会加锁,存在实例就不会加锁了

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

多线程第一次访问的时候只有一个线程会获得锁,其他线程阻塞。
第一个线程创建完对象释放锁后其他线程进入锁,又进行判断,此时instance已经不是null所以其他线程不会再创建实例

图解双重校验锁

1、首次创建有三个线程同步进入
第一个线程获得胜利创建实例,其他线程进入锁后,发现已经创建了实例,所以无奈走了

在这里插入图片描述
2、非首次创建
由于instance不为null,所以后面的线程连锁都见不到
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值