设计模式之单例模式的线程安全

1.线程不安全的单例模式

1.1 创建单例模式类 Singleton

没有加锁,线程不安全,多个线程同时访问,会执行多次创建类对象。

java 复制代码
public class Singleton {
	private static Singleton instance;
	
	private int mCountNumber;
	
	private Singleton() {
		System.out.println(Thread.currentThread().getName() + " Singleton is Instantiated");
	}
	
	public static Singleton getInstance() {
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
	
	public void printCountNumber() {
		System.out.println(Thread.currentThread().getName() + " Singleton current count number is " + mCountNumber++);
	}

}

1.2 多线程访问不安全

getInstance 多次执行了 new Singleton的处理,创建类多个实例,导致 Singleton 的成员变量 mCountNumber 的值也不唯一。

java 复制代码
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("---------------------- main begin ----------------------");
		
		
		for (int i = 0; i < 10; i++) {
			Thread thread = new Thread(() -> {
			    System.out.println(Thread.currentThread().getName() + " 线程运行开始");

			    Singleton.getInstance().printCountNumber();
			    
			    System.out.println(Thread.currentThread().getName() + " 线程运行结束");
			});
			
			thread.start();
		}
		
		System.out.println("---------------------- main end ----------------------");
	}

log输出:

java 复制代码
---------------------- main begin ----------------------
---------------------- main end ----------------------
Thread-4 线程运行开始
Thread-9 线程运行开始
Thread-7 线程运行开始
Thread-8 线程运行开始
Thread-0 线程运行开始
Thread-5 线程运行开始
Thread-3 线程运行开始
Thread-1 线程运行开始
Thread-2 线程运行开始
Thread-6 线程运行开始
Thread-6 Singleton is Instantiated
Thread-5 Singleton is Instantiated
Thread-3 Singleton is Instantiated
Thread-7 Singleton is Instantiated
Thread-9 Singleton is Instantiated
Thread-2 Singleton is Instantiated
Thread-4 Singleton is Instantiated
Thread-0 Singleton is Instantiated
Thread-8 Singleton is Instantiated
Thread-1 Singleton is Instantiated
Thread-4 Singleton current count number is 0
Thread-1 Singleton current count number is 0
Thread-5 Singleton current count number is 0
Thread-5 线程运行结束
Thread-8 Singleton current count number is 0
Thread-6 Singleton current count number is 0
Thread-6 线程运行结束
Thread-9 Singleton current count number is 0
Thread-2 Singleton current count number is 0
Thread-2 线程运行结束
Thread-3 Singleton current count number is 0
Thread-3 线程运行结束
Thread-0 Singleton current count number is 0
Thread-4 线程运行结束
Thread-1 线程运行结束
Thread-7 Singleton current count number is 0
Thread-7 线程运行结束
Thread-8 线程运行结束
Thread-9 线程运行结束
Thread-0 线程运行结束

2.无锁的线程安全单例模式

2.1 创建单例模式类 LockFreeSingleton

通过在声明时直接实例化静态成员的方式,来保证一个类只有一个实例。这种实现方式避免了使用同步锁机制和额外检查判断实例是否被创建。

java 复制代码
public class LockFreeSingleton {
	private static final LockFreeSingleton instance = new LockFreeSingleton();
	
	private int mCountNumber;
	
	private LockFreeSingleton() {
		System.out.println(Thread.currentThread().getName() + " LockFreeSingleton is Instantiated");
	}
	
	public static synchronized LockFreeSingleton getInstance() {
		return instance;
	}
	
	public void printCountNumber() {
		System.out.println(Thread.currentThread().getName() + " LockFreeSingleton current count number is " + mCountNumber++);
	}

}

2.2 多线程访问安全

getInstance 只创建了一个对象,成员变量 mCountNumber 的值也是递增的,每次都不一样,保证类唯一性。

java 复制代码
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("---------------------- main begin ----------------------");
		
		
		for (int i = 0; i < 10; i++) {
			Thread thread = new Thread(() -> {
			    System.out.println(Thread.currentThread().getName() + " 线程运行开始");

			    //Singleton.getInstance().printCountNumber();
			    LockFreeSingleton.getInstance().printCountNumber();
			    
			    System.out.println(Thread.currentThread().getName() + " 线程运行结束");
			});
			
			thread.start();
		}
		
		System.out.println("---------------------- main end ----------------------");
	}

log输出:

java 复制代码
---------------------- main begin ----------------------
---------------------- main end ----------------------
Thread-4 线程运行开始
Thread-7 线程运行开始
Thread-9 线程运行开始
Thread-3 线程运行开始
Thread-0 线程运行开始
Thread-5 线程运行开始
Thread-6 线程运行开始
Thread-2 线程运行开始
Thread-8 线程运行开始
Thread-4 LockFreeSingleton is Instantiated
Thread-1 线程运行开始
Thread-8 LockFreeSingleton current count number is 2
Thread-9 LockFreeSingleton current count number is 1
Thread-6 LockFreeSingleton current count number is 4
Thread-9 线程运行结束
Thread-4 LockFreeSingleton current count number is 0
Thread-2 LockFreeSingleton current count number is 3
Thread-2 线程运行结束
Thread-0 LockFreeSingleton current count number is 6
Thread-7 LockFreeSingleton current count number is 8
Thread-5 LockFreeSingleton current count number is 5
Thread-3 LockFreeSingleton current count number is 7
Thread-3 线程运行结束
Thread-1 LockFreeSingleton current count number is 9
Thread-8 线程运行结束
Thread-6 线程运行结束
Thread-4 线程运行结束
Thread-0 线程运行结束
Thread-7 线程运行结束
Thread-5 线程运行结束
Thread-1 线程运行结束

3.双重校验锁机制的同步锁单例模式

3.1 创建双重校验同步锁单例模式类 DoubleCheckSingleton

在syncchronized 代码块中也需要进行一次检查。

java 复制代码
/**
 * 单例模式
 *
 * 双检锁/双重校验锁(DCL,即 double-checked locking)
 * JDK 版本:JDK1.5 起
 * 是否 Lazy 初始化:是
 * 是否多线程安全:是
 * 实现难度:较复杂
 * 描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
 * getInstance() 的性能对应用程序很关键。
 */
public class DoubleCheckSingleton {
	private volatile static DoubleCheckSingleton instance;
	
	private int mCountNumber;
	
	private DoubleCheckSingleton() {
		System.out.println(Thread.currentThread().getName() + " DoubleCheckSingleton is Instantiated");
	}
	
	public static DoubleCheckSingleton getInstance() {
		if (instance == null) {
			synchronized (DoubleCheckSingleton.class) {
				if (instance == null) {
					instance = new DoubleCheckSingleton();
				}
			}
		}
		return instance;
	}
	
	public void printCountNumber() {
		System.out.println(Thread.currentThread().getName() + " DoubleCheckSingleton current count number is " + mCountNumber++);
	}

}

3.2 多线程访问安全

java 复制代码
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("---------------------- main begin ----------------------");
		
		
		for (int i = 0; i < 10; i++) {
			Thread thread = new Thread(() -> {
			    System.out.println(Thread.currentThread().getName() + " 线程运行开始");

			    DoubleCheckSingleton.getInstance().printCountNumber();
			    
			    System.out.println(Thread.currentThread().getName() + " 线程运行结束");
			});
			
			thread.start();
		}
		
		System.out.println("---------------------- main end ----------------------");
	}

log输出:

java 复制代码
---------------------- main begin ----------------------
Thread-0 线程运行开始
Thread-4 线程运行开始
Thread-1 线程运行开始
Thread-2 线程运行开始
Thread-3 线程运行开始
Thread-0 DoubleCheckSingleton is Instantiated
Thread-5 线程运行开始
Thread-6 线程运行开始
Thread-7 线程运行开始
Thread-8 线程运行开始
---------------------- main end ----------------------
Thread-9 线程运行开始
Thread-4 DoubleCheckSingleton current count number is 1
Thread-9 DoubleCheckSingleton current count number is 9
Thread-4 线程运行结束
Thread-0 DoubleCheckSingleton current count number is 0
Thread-3 DoubleCheckSingleton current count number is 4
Thread-6 DoubleCheckSingleton current count number is 6
Thread-2 DoubleCheckSingleton current count number is 3
Thread-1 DoubleCheckSingleton current count number is 2
Thread-8 DoubleCheckSingleton current count number is 8
Thread-8 线程运行结束
Thread-5 DoubleCheckSingleton current count number is 5
Thread-5 线程运行结束
Thread-7 DoubleCheckSingleton current count number is 7
Thread-9 线程运行结束
Thread-0 线程运行结束
Thread-3 线程运行结束
Thread-6 线程运行结束
Thread-2 线程运行结束
Thread-1 线程运行结束
Thread-7 线程运行结束

参考:

https://www.runoob.com/design-pattern/singleton-pattern.html

相关推荐
夏天拐跑了西瓜16 分钟前
Spring Cloud 微服务实战(三):一个服务挂了,凭什么拖垮整个系统?Sentinel 限流熔断实战
java·spring cloud·微服务
2601_9672642834 分钟前
Jetpack Compose 实践指南:从入门到进阶
java·学习
m0_587383001 小时前
社区家政系统开发实战:从需求分析到上线部署全指南
java·spring boot·spring·需求分析
凤山老林1 小时前
动态 i18n 体系落地:Spring Boot 多租户热加载与前后端协同实践
java·spring boot·后端·i18n
白露与泡影2 小时前
解密 Pi 的 Harness 工程:Agent 会话如何实现持久化与恢复
java·人工智能·算法
Zane19943 小时前
HashMap 为什么要在长度16、容量必须是2的幂这些细节上较劲
java·后端
长谷深风1113 小时前
为什么你的 Tool 总被模型选错?
java·大数据·ai·llm·ai agent·工具设计·agent设计
莫得感情 o4 小时前
并发 14 · 收官:虚拟线程与结构化并发
java·并发
聚美智数4 小时前
图片水印-图片剪裁-图片缩放API接口介绍
java·服务器·数据库
xierui1231235 小时前
AI Agent 隐私架构:本地化重点为什么是登录态与执行权限
java·人工智能·网络安全·架构