Java 单例模式最完美的写法

单例模式

是设计模式的中的一种。所谓单例模式,就是就是整个系统中对象仅此一个,不会有重复的对象生成。

1.  懒汉式

顾名思义,就是比较懒,当你使用的我现场去创建对象。

// 单例对象
class SingleObject{

	private static SingleObject instance;
	//构造方法私有化
	private SingleObject(){
		System.out.println("我是 SingleObject 的构造方法");
	}
	
	public static SingleObject getInstance() {
		if(instance==null) {
			instance = new SingleObject();
			return instance;
		}
		return instance;
	}
}

2. 饿汉式

顾名思义,就是时刻保持警惕,一上来就把对象给你创建好,就等着你使用。

// 单例对象
class SingleObject{

	private static SingleObject instance = new SingleObject();;
	//构造方法私有化
	private SingleObject(){
		System.out.println("我是 SingleObject 的构造方法");
	}
	
	public static SingleObject getInstance() {
		return instance;
	}
}

注意:在单线程中 懒汉式 和 饿汉式 可以解决问题,但是在多线程的环境中,这么些是有问题的!

为了看着清晰,我们现场来测试一下:

// 单例对象
class SingleObject{

	private static SingleObject instance;
	//构造方法私有化
	private SingleObject(){
		System.out.println( Thread.currentThread().getName() + " 我是 SingleObject 的构造方法");
	}
	
	public static SingleObject getInstance() {
		if(instance == null) {
			instance = new SingleObject();
			return instance;
		}
		return instance;
	}
}
// 单例模式:饿汉式多线程测试
public class SingleDemo {
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(()->{
				SingleObject.getInstance();
			},i+"").start();
		}
	}
}

执行结果:

所以结合多线程环境下,创建了一种新的模式

3. (DCL)双检锁

// 单例对象
class SingleObject{

	private static SingleObject instance;
	//构造方法私有化
	private SingleObject(){
		System.out.println( Thread.currentThread().getName() + " 我是 SingleObject 的构造方法");
	}
	
	public static SingleObject getInstance() {
		if(instance == null) {
			synchronized (SingleObject.class) {
				if(instance == null) {
					instance = new SingleObject();
					return instance;
				}
			}
		}
		return instance;
	}
}

双检锁(DCL),又叫双重校验锁,综合了懒汉式和饿汉式两者的优缺点整合而成。但是这个机制不一定线程安全,原因是因为它有指令重排序的存在,所以,需要加上 volatile 来禁止指令重排序。如果不了解指令重排,可以看看博客:volatile 关键字

 所以说需要禁止指令重排,保证多线程下的语义一致性,如果不加,就有一定的几率出现线程不安全问题。

4. volatile 版本 DCL(最完美)

// 单例对象(双检锁+volatile)推荐使用
class SingleObject{

	// 加上 volatile 关键字,禁止指令重排
	private static volatile SingleObject instance;
	//构造方法私有化
	private SingleObject(){
		System.out.println( Thread.currentThread().getName() + " 我是 SingleObject 的构造方法");
	}
	
	public static SingleObject getInstance() {
		if(instance == null) {
			synchronized (SingleObject.class) {
				if(instance == null) {
					instance = new SingleObject();
					return instance;
				}
			}
		}
		return instance;
	}
}
发布了40 篇原创文章 · 获赞 20 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/cong____cong/article/details/104345239