单例:饿汉式和懒汉式各自的优缺点

本文深入解析单例模式的实现方式,包括饿汉式、懒汉式及静态内部类等,探讨其优缺点,并通过代码示例说明如何在多线程环境中确保线程安全。

单例模式应用于一个类只有一个实例的情况,并且为其实例提供一个全局的访问点

  • 特点:
  1. 一个类只有一个实例

  2. 自己创建这个实例

  3. 整个系统只能用这个实例

  • 应用场景
    外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。
    内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件。

1. 饿汉式:单例实例在类装载(ClassLoader)时就构建,急切初始化。(预先加载法)

		class Singleton {
				//1,私有构造函数
				private Singleton(){}
				//2,创建本类对象
				private static Singleton s = new Singleton();
				//3,对外提供公共的访问方法,此处只需要get方法,不需要set方法来修改值
				public static Singleton getInstance() {		//获取实例
					return s;
				}
			}
 
  • 优点 :
    1.线程安全
    2.在类加载的同时已经创建好一个静态对象调用时反应速度快
  • 缺点 :
    资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化

2. 懒汉式:单例实例在第一次被使用时构建,延迟初始化。

		//懒汉式,单例的延迟加载模式:使用时再new对象
			class Singleton {
				//1,私有构造函数
				private Singleton(){}
				//2,声明一个本类的引用,不创建对象
				private static Singleton s;
				//3,对外提供公共的访问方法
				public static Singleton getInstance() {
					if(s == null)
						//线程1等待,线程2等待,苏醒后都会创建对象,即>=1
						s = new Singleton();
					return s;	
				}
			}
			/*
			 * 饿汉式和懒汉式的区别
			 * 1,饿汉式是空间换时间,懒汉式是时间换空间
			 * 2,在多线程访问时,饿汉式不会创建多个对象,而懒汉式有可能会创建多个对象
			 */

懒汉式在单个线程中没有问题,但在多线程就可能会出现两个或多个Singleton2实例情况,虽然后面实例化的Singleton2会覆盖前面实例化的Singleton2,但最好避免这样的情况

  • 改进方式就是加锁synchornized:双重检测
public class Singleton {	
    private volatile static Singleton uniqueInstance;
	//使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
	//指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得 还没有初始化的实例。
    private Singleton() {
    }

    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {//第一个 if 语句用来避免 uniqueInstance 已经被实例化之后的加锁操作
            synchronized (Singleton.class) {//静态,同步用.class字节码文件
                if (uniqueInstance == null) {//第二个 if 语句进行了加锁,所以只能有一个线程进入,就不会出现 uniqueInstance == null 时两个线程同时进行实例化操作。
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
 	   }
	}

  • 优点:
    资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法
  • 缺点:
    第一次加载时不够快多线程使用不必要的同步开销大

3.静态内部类

class Singleton5 {
	private Singleton5() {
	}

	private static class SingletonHelp {
		static Singleton5 instance = new Singleton5();
	}

	public static Singleton5 getInstance() {
		return SingletonHelp.instance;
	}
}
 
  • 优点:
    资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法
  • 缺点:
    第一次加载时反应不够快

总结:一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值