Java单例设计模式之“饿汉与懒汉”

目录

前言

单例模式

实现步骤

方法调用·饿汉

拓展

懒汉

懒汉式的安全问题

解决方案:加锁

 性能问题

解决方法


前言

设计模式:不是技术,而是开发人员解决特定问题实现的写代码的经验

所有的设计模式核心技术,就是面向对象。

Java设计模式共23种,分为:

创建型,行为型,结构型


单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。

保证一个类的对象在内存中的唯一性


实现步骤

  • 私有修饰构造方法
  • 自己创建自己的对象
  • public class Single {
        private Single(){}    //私有修饰构造方法
    
        private Single single = new Single();    //自己创建自己的对象
    }
  •  书写get方法,返回本类对象(原因:权限为private)
    public  Single getSingle(){
            return single;

方法调用·饿汉

想要调用此方法,则需要对象,但单例要保证对象唯一性,那我们就换一个方法:使用静态

public static Single getSingle(){
        return single;

静态不能返回非静态,所以上面我们也需要加static。我们再新建一个类来测试一下

public class Single {
    private Single(){}    //私有修饰构造方法

    private static Single single = new Single();    //自己创建自己的对象
}
public class Text {
    public static void main(String[] args) {
        //静态方法,获取Single类的对象
        Single instance = Single.getInstance();
        System.out.println("instance = " + instance);
    }
}
1.1饿汉输出显示

此时不管我们instance = Single.getInstance();多少次

它的哈希值都是一样的,说明对象的唯一性,但如果new了一个新对象,哈希值就会改变


 拓展

这种方式又叫“饿汉”,static静态的特点:加载速度很快,一调用静态方法,这个类就进内存了,紧接着就初始化了这个静态成员single去new对象,显得很急切地样子  (着急吃对象)


懒汉

“懒汉”,又叫对象的延迟加载,与“饿汉”不同的地方,在于第二步

“饿汉”是自己创建自己的对象

“懒汉”是创建本类的成员变量,不new对象 

 不直接new对象的好处是,当类中有多个方法时,不管会不会用上,“饿汉”一开始就会创建对象,而“懒汉”在需要调用方法时,才会进行new对象,节省了内存

 private static Single single = null;

而创建对象的操作,就置入get方法中,而if判断语句也可保证new对象的唯一性

public class Single {
    private Single(){}

    private static Single single = null;

    public static Single getInstance(){
        //判断变量s,是null就创建对象
        if (single==null){
            single = new Single();
        }
        return single;
    }
}
1.2懒汉输出显示

懒汉式的安全问题

当多线程运行时,一个线程进入if判断为null,还未进行new对象的语句,另一线程更快,也进行了判断,先一步完成new对象,此时,前一个线程要出判断语句,必然也要new一个对象,此时就产生了对象创建多次的问题。


解决方案:加锁

先找到共享数据(同步代码块),然后加锁,由上面分析可知,if判断语句就是它们的共享数据

if (single==null){
            single = new Single();
        }

我们就用synchronized把它括住,锁就使用本类就行

public static Single getInstance(){
        //判断变量s,是null就创建对象
        synchronized (Single.class){
            if (single==null){
                single = new Single();
            }
        }
        return single;
    }

把锁加上后,即使前一个线程已进入判断语句,CPU找了另一个线程想进来,但锁在前一个线程的身上,只要这个线程未出去,锁就不会还回来,其他线程也就只能在共享数据外等待

当然,加锁会让效率变低,但可以保证安全性

程序慢点没关系,但一定要安全!!!


 性能问题

第一个线程获取锁,创建对象,返回对象.第二个线程调用方法的时候,变量s已经有对象了,根本就不需要再进同步,也不需要判断null,直接return才是最高效的

解决方法

使用双重if判断,解决上文效率问题。

多加一个if判断,只要有了一个对象,后来的线程就不再进入同步,直接跳过锁返回,即使两个线程都同时通过了第一个if判断,在锁内部仍有一个if判断,强制把多个锁前后分开,先进锁的创建对象,进锁的其他线程在第二个判断时不为null,直接return。

public static Single getInstance(){
        if (single==null) {    //第一重判断
            //判断变量s,是null就创建对象
            synchronized (Single.class) {
                if (single == null) {    //第二重判断
                    single = new Single();
                }
            }
        }
        return single;
    }

今天的Java文章分享就到此结束了, 喜欢的小伙伴记得一键三连,点赞收藏评论,如果想了解更多内容,可以用未来百万富豪的手指,点点小小的关注!你们的支持就是我最大的动力!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小泥人Hyper

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值