极简设计模式 - 单例模式


前言

设计模式系列目录
单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供全局访问点。两种实现:饿汉模式(快速加载)懒汉模式(延迟加载到使用时)

小声bb:同志们,场景自己琢磨吧。这里说啥也不如自己实践一下。


类图

类图好像有点抽象?我之前在类图的几种线条中说过这个自关联。理解不了也没关系,我们直接看代码。
单例模式UML

代码

代码提交到Github上了
https://github.com/software-market/design-pattern(欢迎star,谢谢各位大佬。)
单例模式代码不多,在这展示一下。掌握精髓后是不是感觉“就这”?对,一点都不神秘。

饿汉模式

public class Singleton {

	// 构造方法私有化,保证单例
	private Singleton() {
	}

	// 自己创建一个实例,私有静态
	private static final Singleton instance = new Singleton();

	// 全局访问点
	public static Singleton getInstanse() {
		return instance;
	}

	public String sayHello() throws Exception {
		return LocalDate.now() + " - hello";
	}
}

懒汉模式 - 初级版本

懒汉模式,延迟实例创建。但存在线程安全的问题:并发环境下会创建出多个实例

public class Singleton {

	// 构造方法私有化,保证单例
	private Singleton() {
	}

	// 自己创建一个实例,私有静态
	private static Singleton instance;

	// 全局访问点
	public static Singleton getInstanse() {
		if(instance == null)
			instance = new Singleton(); // 延迟加载
		return instance;
	}

	public String sayHello() throws Exception {
		return LocalDate.now() + " - hello";
	}
}

懒汉模式 - 究极版本

双重检查锁(DCL)版本。
第一重缩小锁粒度,减少锁操作。
第二步,这步在同步区域,保证实例为空才会去创建。
volatile关键字,这一步保证new操作是一个原子性操作,避免被指令重排影响,感兴趣的自行百度。

public class Singleton {

	//构造方法私有化,保证单例
	private Singleton() {
	}

	// 自己创建一个实例,私有静态
	private static volatile Singleton instance;

	// 全局访问点
	public static Singleton getInstanse() {
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		}
		return instance;
	}

	public String sayHello() throws Exception {
		return LocalDate.now() + " - hello";
	}
}

懒汉模式 - 内部类版本

public class Singleton {

	// 构造方法私有化,保证单例
	private Singleton() {
	}

	// 内部类的方式创建
	private static final class creater {
		private static final Singleton INSTANCE = new Singleton();
	}

	// 全局访问点
	public static Singleton getInstanse() {
		return creater.INSTANCE;
	}

	public String sayHello() throws Exception {
		return LocalDate.now() + " - hello";
	}
}

以下测试代码示例,多线程问题不在此赘述。

public class SingletonTest {

	@Test
	public void test() {
		try {
			String s = Singleton.getInstanse().sayHello();
			System.out.println(s);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

输出如下

2021-02-02 - hello

总结

  1. 多线程问题不能等到出现时才考虑,我们必须假定所有的程序都是多线程的,然后选择合适的方案去创建单例。
  2. 在1.4及更早版本的java中,volatile关键字的实现会导致它失效。
  3. 不同的类加载器,也会导致实例被重复创建。
  4. java1.2必须使用内存来保存单例的引用,不然会被垃圾回收机制给干掉。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值