线程安全之设计模式


单例模式

1.是什么

单例模式,本质上就是借助变成语言自身的语法特性,强行限制某个类,不能创建多个实例

由static引入单例模式

static关键字修饰的成员/属性 变成了类成员/类属性
其实当属性变成类属性的时候,此时就已经是“单个实例”

jvm针对某个.class文件只会加载一次,也就只有一个类对象,类对象上面的成员(static修饰)也就只有一份了

c语言中的static

1.修饰局部变量:改变了变量的声明周期
2.修饰全局变量,改变了变量的作用域
3.修饰函数,改变了函数的作用域

2.单例模式创建

饿汉模式

class Singleton{
    private  static Singleton instance=new Singleton();
    public static Singleton getInstance(){
        return instance;
    }
    //把 构造方法 设为private 此时在类的外面,就无法继续new 实例了
    private Singleton(){

    }
}
public class demo20{
    public static void main(String[] args) {
        //如果代码这么些,就违背初衷,就应该禁止在这个类的外部被new
//        Singleton instance2=new Singleton();
        Singleton instance=Singleton.getInstance();
    }
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
上述代码里写的实现单例模式的方式,叫做饿汉模式

类加载阶段创建的实例,创建实例的时机非常早,非常急迫

懒汉模式

在这里插入图片描述

首次调用getinstance的时候才会触发,后续在调用getinstance就立即返回对象 因此,懒汉模式创建实例晚,但是效率更高

在这里插入图片描述

为什么懒汉模式的效率更高:

如果整个代码后续没人调用getInstance,这样就把构造实例的过程给省下来了
或者即使有代码后续调用getInstance,但是调用的时机,比较晚,这个时候,创建实例的时机也就延迟了,就和其他耗时操作岔开了(一般程序刚启动时,要初始化的东西很多,系统资源紧张

饿汉模式,懒汉模式谁更安全

考虑到这俩代码是否线程安全,本质上是在考虑,多个线程同时调用instance,是否会有问题
在这里插入图片描述
在这里插入图片描述
加锁修改懒汉模式使其安全
在这里插入图片描述
这样写虽然解决了线程安全问题,但是导致后续线程已经安全的时候,仍然还得加锁
线程不安全,只是实例创建之前(首轮调用时候)才会触发

修改代码:
实例没有创建之前,加锁,
实例创建之后,不加
在这里插入图片描述
中间隔着一个加锁操作,这就意味着这俩个if执行的时间间隔可能是沧海桑田(加锁可能会产生竞争,竞争就会导致阻塞,阻塞的话,啥时候唤醒,不一定了,有可能在这过程中另一个线程竞争到锁已经创建出了实例

上述代码还会触发指令重排序问题:

new 操作的本质上也是三个步骤:
1.申请内存,得到内存首地址
2.调用构造方法,来初始化实例
3.把内存的首地址赋值给instance对象引用

如果先执行1,3在2执行之前,就得到了不完全的对象,
t2线程里面getInstance会认为instance非空,就直接返回Instance,并且在后续可能会针对instance进行解引用操作(使用里面的属性/方法)
只是有内存,但是内存上的数据是无效的

再次修改:
优化方案:volatile关键字(内存可见性,指令重排序):

> package Threading; //线程安全的懒汉模式 class SingletonLazy{
>     private volatile static SingletonLazy instance=null;
>     public static SingletonLazy getInstance(){
>         if(instance==null){
>             synchronized (Singleton.class){
>                 if(instance==null){
>                     instance=new SingletonLazy();
>                 }
>             }
>         }
>         return instance;
>     }
>     private SingletonLazy(){}; } public class demo21 {
>     public static void main(String[] args) {
>         SingletonLazy instance=SingletonLazy.getInstance();
>     } }

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值