Java:设计模式之 单例模式

单例模式确保一个类只有一个实例,并提供全局访问点。关注点包括延迟加载、线程安全和效率。常见应用场景如任务管理器、回收站、配置文件读取等。本文介绍了五种单例模式实现:饿汉式、懒汉式、双重检测锁模式、静态内部类单例和枚举单例,其中静态内部类和枚举单例兼顾线程安全和延迟加载。

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

单例模式

保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

单例设计模式主要关心的几个点:

1.延迟加载

2.线程安全

3.效率

特点

  1. 该类在全局只有一个实例。

  2. 只提供一个访问该实例的全局访问点。

应用场景

  1. Windows 的任务管理器 就是最典型的单例模式
  2. Windows 的回收站也是典型的单例应用
  3. 项目中,读取配置文件的类,一般也只有一个对象,没必要每次使用配置文件数据,每次new一个对象去读取
  4. 网站的计数器,一般也是采用单例模式实现,否则难以同步
  5. 应用程序的日志应用,由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加
  6. 数据库连接池的设计一般也是采用单例设计模式,因为数据库连接是一种数据库资源
  7. 操作系统的文件系统,也是大的单例设计模式实现的具体例子,一个操作系统只能有一个文件系统
  8. Servlet编程中的 Application 、Servlet 也是单例的典型应用
  9. Spring MVC/struts1 框架中,控制器对象也是单例

单例模式的优点

​ 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决

​ 单例模式可以在系统设置全局的访问点,优化共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理

常见的五种单例模式实现方式

饿汉式(线程安全,调用效率高,但是不能延时加载)

懒汉式(线程安全,调用效率不高,但是可以延时加载)

双重检测锁式(由于JVM地层内部模型原因,偶尔会出问题。不建议使用)

静态内部类式(线程安全,调用效率高,也可以延时加载)

枚举单例(线程安全,调用效率高,不能延时加载)

饿汉式

饿汉式实现的一般步骤:

  1. 构造方法私有
  2. 类的内部创建私有对象
  3. 提供对外的访问方法

代码实现

public class Demo01 {
	public static void main(String[] args) {
		EagerSingleton instance = EagerSingleton.getInstance();
		EagerSingleton instance2 = EagerSingleton.getInstance();
		System.out.println(instance == instance2); // true
	}
}

class EagerSingleton {
	// 2.类的内部创建私有对象
	private static EagerSingleton es = new EagerSingleton();
	
	// 1.构造方法私有
	private EagerSingleton() {}
	
	// 3.提供对外的访问方法
	public static EagerSingleton getInstance() {
		return es;
	}
}

特点:

  1. 类初始化时,立即加载

  2. 饿汉式单例模式代码中,static变量会在类装载时初始化

    此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,该类肯定不会发生并发访问问题。因此,可以省略 sychronized 关键字。

  3. 如果只是加载本类,而不是调用公共方法,甚至永远没有调用,则会造成资源浪费

懒汉式

懒汉式实现的一般步骤:

  1. 构造方法私有
  2. 类的内部定义对象
  3. 提供对外的访问方法

代码实现

public class Demo02 {
	public static void main(String[] args) {
		LazySingleton instance = LazySingleton.getInstance();
		LazySingleton instance2 = LazySingleton.getInstance();
		System.out.println(instance == instance2); // true
	}
}

class LazySingleton {
	private static LazySingleton ls;
	
	private LazySingleton() {}
	
	public static synchronized LazySingleton getInstance() {
		if (ls == null) {
			ls = new LazySingleton();
		}
		return ls;
	}
}

特点:

  1. 懒加载,getInstance方法调用的时候再加载该类
  2. 资源利用率提高了
  3. 每次调用getInstance()方法都要同步,并发效率低

双重检测锁模式

这个模式将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。

问题:由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题,不建议使用

代码实例:

class DoubleCheckLockSingleton {
	private static DoubleCheckLockSingleton instance = null;
	
	private DoubleCheckLockSingleton() {}
	
	public static DoubleCheckLockSingleton getInstance() {
		if (instance == null) {
			DoubleCheckLockSingleton singleton;
			synchronized(DoubleCheckLockSingleton.class) {
				singleton = instance;
				if (singleton == null) {
					synchronized(DoubleCheckLockSingleton.class) {
						if (singleton == null) {
							singleton = new DoubleCheckLockSingleton();
						}
					}
					instance = singleton;
				}
			}
		}
		return instance;
	}
}

静态内部类单例模式

特点:

  1. 由于静态内部类在外部类被加载的时候不会被立刻加载,只有当访问内部类成员的时候才会加载内部类,所以这里也是延迟加载

2.这里使用静态成员是天然的线程安全

3.由于getInstance方法没有同步,所以性能会很高

4.外部类没有static属性,则不会像饿汉式那样立即加载对象

5.只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的,instance同时也是static final 修饰,保证了内存中只有一个实例存在,而且只能被赋值一次,从而保证了线程安全,兼备了并发安全,高效调用,和延迟加载的优势

class StaticInnerClassSingleton {
	
	private StaticInnerClassSingleton() {}
	
	private static class InnerClass {
		private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
	}
	
	public static StaticInnerClassSingleton getInstance() {
		return InnerClass.instance;
	}
}

枚举

枚举就是单例模式的一种体现。天然安全,天然防止反射和反序列化漏洞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值