关于Java中单例模式(饿汉模式和懒汉模式)的简析

目录

一.什么是单例模式

二.饿汉模式和懒汉模式

饿汉模式

代码

懒汉模式

代码

关于多线程安全的问题

如何解决懒汉模式多线程安全问题

双if判断


一.什么是单例模式

简单来说,就是我们在程序中通过代码进行限制,在该程序中

只能创建一个对象

二.饿汉模式和懒汉模式

因为只能创建一个对象,所以对于我们而言就有两种方式

第一种方式

饿汉模式

让程序自动类中创建唯一的对象

在类外不能被创建

代码

class Student{

//此处在类的内部一开始就自己创建了唯一的Student对象
    public static Student st = new Student();

//提供private构造方法,让其在类外不能被调用
    private Student(){}

//提供getInstance方法,以便获取唯一的Student对象
    public static Student getInstance(){
        return st;
    }
}
public class Main {
    public static void main(String[] args) {

//此处的st2,和st3都指向唯一的st对象,还是只存在唯一一个对象
        Student st2 = Student.getInstance();
        Student st3 = Student.getInstance();
    }
}

第二种方式

懒汉模式

就是程序在自己内部不创建唯一对象

而是我们需要的时候再在类外面new那个唯一的对象

这种方式就叫做懒汉模式

代码

class Teacher{

//将te指向空,等到get的时候再进行实例化,这里是没有指向任何对象
    private static Teacher te = null;

//避免通过new的方式创建其他实例,只能通过get方式获取唯一实例
    private Teacher(){}

//通过get创建唯一对象
    public static Teacher getInstance(){
        if(te == null){
            te  = new Teacher();
        }
        return te;
    }
}
public class demo1 {
    public static void main(String[] args) {

//调用才创建对象
        Teacher te1 = Teacher.getInstance();
    }
}

关于多线程安全的问题

其实我们大体上就要记住一点

多线程同时修改同一份变量大概率就会发生线程安全的问题

所以在上述代码中

我们的饿汉模式在多线程的情况下

他不管调用几次都只是在返回已经创建好的那个唯一对象

只是相当于获取

并没有进行任何修改操作

但是在懒汉模式的多线程下

我们是进行了判断,然后创建的唯一对象,创建这个操作就是对数据进行了修改

那么多个线程同时对一个数据进行修改,那么就会发生多线程安全的问题

所以

饿汉模式没有多线程安全问题

懒汉模式多线程安全问题

如何解决懒汉模式多线程安全问题

加锁

加锁

还是(* * *)加锁

我们最优先想到的就是直接在get方法那里加上synchronized

class Teacher{
    private static Teacher te = null;
    private Teacher(){}
//直接加上一把锁
    public static synchronized Teacher getInstance(){
        if(te == null){
            te  = new Teacher();
        }
        return te;
    }
}

但是这样是会有问题的

因为此处的操作并不是原子性,那么如果是多线程进行操作,可能会出现下面的情况

 也就是说,我们可能会同时返回两个对象回去

为了避免这种情况,我们还需要加入关键字volatile(禁止指令重排序与保证可见性)

class Teacher{
//这里加上volatile 后就没有排序的问题了
    private static volatile Teacher te = null;
    private Teacher(){}
    public static synchronized Teacher getInstance(){
        if(te == null){
            te  = new Teacher();
        }
        return te;
    }
}

实际上到了这一步

我们已经解决安全的问题了

但是为了进一步提升效率,我们采取了双if判断的方式

双if判断

我们把锁加在了if判断语句这里,而取消了get方法的锁

让多个线程同时调用该方法,如果没有被创建,则执行上锁的new对象操作

如果已经被创建则返回该对象

class Teacher{
    private static volatile Teacher te = null;
    private Teacher(){}
    public static  Teacher getInstance(){

//第一个if判断,如果已经创建锁,就直接跳到最后的返回
        if(te == null){

//多个线程在调用get的时候,都卡在这里竞争这把锁
//竞争成功的创建唯一对象,并释放锁
//其他线程拿到被释放的锁之后进去查看,发现第一个线程已经创建了唯一对象
//不满足第二个if条件,又跳到最后返回
            synchronized(Teacher.class){
                if(te == null){
                    te  = new Teacher();
                }
            }
        }
        return te;
    }
}

但我个人感觉,用前面的volatile和对get方式加锁已经足够了

虽然效率比双if要低一些但已经解决了我们的多线程安全问题

双if判断只能说锦上添花吧

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值