【单例模式-饿汉模式和懒汉模式】

文章介绍了设计模式的概念和分类,重点讲解了单例模式,包括饿汉模式和懒汉模式。饿汉模式在类加载时就创建实例,线程安全但可能导致资源浪费;懒汉模式延迟实例化,线程不安全,但更节约资源。文中还提供了线程安全的懒汉模式实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

什么是设计模式?

设计模式是面向对象编程中的一种解决问题的方案或方法,它提供了一种在特定情况下进行软件设计的最佳实践,能够提高软件在可维护性、可重用性、可扩展性、可读性和可靠性等方面的质量和效率。设计模式是经过实践验证的,被广泛应用的在面向对象编程中的解决方案。根据功能和特性的不同,设计模式可分为三类:

  1. 创建型模式:用于对象的创建,包括单例模式工厂模式、抽象工厂模式、建造者模式和原型模式等。

  2. 结构型模式:用于对象和类之间的组织关系,包括适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式和享元模式等。

  3. 行为型模式:用于描述对象和类之间的通信关系,包括观察者模式、模板方法模式、命令模式、状态模式、职责链模式、策略模式、访问者模式、备忘录模式、迭代器模式和解释器模式等。

在实际软件开发中,设计模式可以有效避免重复造轮子,提高代码的可读性和可维护性。同时,它也能够帮助开发者更加深入理解程序设计中的原则和思想。


提示:以下是本篇文章正文内容,下面案例可供参考

一、单例模式

单例模式是指一个类只能够创建一个对象实例,该实例可以被全局访问。

  • 简单来说就是,借助java语法,保证某个类,只能够创建出一个实例,不能new多次。

  • 有效避免了重复创建对象,节省了系统资源,同时也能够避免多个实例对象之间产生矛盾和冲突。

  • 例如:JDBC中的DataSource就只需要一个。

具体的例子:打开计算机上硬盘内的文件,以不同的方式显示到屏幕上

饿汉:一次性把所有的文件内容都读取到内存中,全部显示到屏幕上(可能会导致内存占用爆满,造成电脑卡死)

懒汉:只读取一小部分,把当前的屏幕填充上,如果用户点击了翻页或滑动了滚动条,再读取剩余的一部分显示到屏幕上。(你看多少,我给多少,充分节约资源)


饿汉模式(急迫)

由于他是一个饿汉,非常急迫的想要得到食物,不管好不好吃,能不能吃,先到胃里再说,(即不管该类能不能用到,我先创建了再说,不用就一直放着)就对应了类加载的同时, 即创建实例。

代码示例

//饿汉模式
//把这个类设置为单例
class Singleton {
    //被static修饰,该属性是类的属性(类对象)
    //JVM中,每个类的类对象只能有唯一一份,因此,类对象里的这个成员,就是唯一的一份
    private static Singleton instance = new Singleton();//唯一实例的本体

    public static Singleton getInstance() {//获取到实例的方法
        return instance;
    }

    //将构造方法设置为private,禁止外部new实例,保证唯一
    private Singleton(){}
}


public class ThreadDemo {
    public static void main(String[] args) {
        //此时s1和s2是同一个对象
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        
		//new不成功,Singleton() 在 Singleton 中是 private 在访问控制
        //Singleton s3 = new Singleton();
        System.out.println(s1 == s2);//true,证明是同一个实例
    }
}

特点

  • 单线程和多线程中天生安全,只有使用对象的操作,没有创建对象的操作。

  • 由于一次性加载出所有的类,可能会让初始化的效率低一些。

懒汉模式(从容)

线程不安全的版本

class Singleton {
	private static Singleton instance = null;
	private Singleton() {}
	
	public static Singleton getInstance() {
		if (instance == null) {
		instance = new Singleton();
		//一个new操作会被分为三步,任意一步都有可能被切换线程,导致出错(new出多个Singleton导致出错)
		//1. 在内存中为对象分配空间;
		//2. 对象的属性被初始化为默认值,如int类型的默认值为0,boolean类型的默认值为false等;
		//3. 执行对象的构造函数,进行初始化操作。
	}
	return instance;
	}
}

解决方法:

线程安全的版本

class SingletonLazy {
        volatile private static SingletonLazy instance = null;//volatile保证new的过程,不会指令重排序

        public static SingletonLazy getInstance() {
            if (instance == null) {//减少加锁的次数,不为空不必再加锁
                synchronized (SingletonLazy.class) {//保证多线程下,不会创建多个对象
                    if (instance == null) {//判断两次,保证多线程只有一个对象
                        instance = new SingletonLazy();
                    }
                }
            }
            return instance;
        }

        private SingletonLazy() {};
}

public class ThreadDemo {
    public static void main(String[] args) {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();

        System.out.println(s1 == s2);
    }
}

特点:

  1. 加锁,把ifnew变成原子操作

  2. 双重if,如果实例已经被创建了,在第一个if中就会结束,不会尝试加锁,减少了不必要的加锁操作,减少了开销

  3. 使用volatile禁止指令重排序,保证后续的线程拿到的是完整对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值