(多线程)单例模式

目录

🔥饿汉模式

💧结果

🔥懒汉模式

💧线程不安全

加锁

 双重if

 防止指令重排序

🔥总结


        单例模式是一种设计模式,设计思路,我们这里主要学习了其中的饿汉模式和懒汉模式。其中,饿汉模式天生是线程安全的,懒汉模式则需要我们通过学过的方法保证其的线程安全。

饿汉模式

什么是饿汉模式,就如字面意思,表示干什么都很着急,不管用不用都需要提前准备好

例如,读取硬盘中文件的内容并显示出来

饿汉模式:将文件中的内容都读到内存中并一股脑全显示出来。如果文件内容比较大,这样势必                     会让内存吃紧,导致卡顿。

public class Singleton {
   private static Singleton singleton = new Singleton();
   public static Singleton getSingleton(){
       return singleton;
   }
   //手动将构造方法权限改为private,外部无法再new
   private Singleton(){

   }
   //随便写个方法,方便观察
    public int test(int n){
       return n*2;
    }
}

使用static修饰,表示类属性这样保证问我们创建出来的是唯一实例对象。

通过get方法来获取引用。

将构造方法设为private,外部无法通过构造方法创建其他实例对象。也保证了单例模式的唯一实例

public class Main {
    public static void main(String[] args) {
       Singleton instance =  Singleton.getSingleton();
        System.out.println(instance.test(100));
    }
}

结果

饿汉模式本身是线程安全的, 我们无需使用加锁之类的方法保证线程安全。

懒汉模式

懒汉模式就与饿汉模式相反,饿汉模式是提前将需要的都加载上,而懒汉模式就是非必要不创建,只有在需要使用实例对象时才会创建

例如,从硬件中读取文件中的内容并显示出来

懒汉模式:读取文件中的一部分并显示出来,当想要看后面的内容时,在从硬盘中读再显示。

public class LazySingleton {
    private static LazySingleton lazySingleton = null;

    public static LazySingleton getLazySingleton(){
       
                if(lazySingleton == null){
                    lazySingleton = new LazySingleton();
                }
     
        return lazySingleton;
    }

    private LazySingleton(){

    }
}

跟饿汉模式相比,我们在加载类的时候并没有就创建出实例,而是先设置为null,当调用到了get方法,也就是说需要用到了实例对象,这时候我们再创建实例对象

线程不安全

加锁

       在多线程环境下,由于线程的抢占式执行,例如t1线程在执行完目前代码的if之后还没有进行实例化对象就被调走,而t2线程来了,完成了new操作,此时t1线程回到cpu上继续执行也进行了new操作,就会产生两个不同的实例对象

       所以,为了解决上面问题,我们就需要保证判断和new操作的原子性,也就是针对这段逻辑进行加锁(synchronized)。

 双重if

       我们仔细想后便知道,出现创建两个不同的实例对象的情况只会在第一次创建对象的时候。加锁是一个低效的操作,但是后续使用中并不会出现创建两个对象的情况,所以我们需要使用双重if来提高效率(非必要,不加锁)。

       此时内外两个if判断的条件虽然一样,但是两个if的作用,解决的问题不同,两个if缺一不可,各自有各自的作用。第一个if防止重复加锁,第二个if保证是否要创建实例对象

 防止指令重排序

       我们知道 new 操作并不是一步操作,在执行的时候会分为三步执行,先申请内存空间,再通过构造方法创建实例对象,最后将内存地址赋值给引用

       针对这个问题我们可以使用volatile来解决。

总结

       饿汉模式天生的是线程安全的。不需要使用加锁,volatile等一些操作。 但是饿汉模式的缺点也很明显,就是创建实例对象的时机太早了,任何操作的作用都是一次性要完成,可能导致内存不够,卡顿等问题。

懒汉模式并不是线程安全的,通过上面分析,我们需要使用三步来保证线程安全。

1.加锁,保证第一次创建实例对象的操作原子性。

2.双重if,非必要不加锁,保证重复的加锁操作。

3.volatile防止指令重排序(new操作),保证后续能拿到完整的对象。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值