写一个高并发下面的单例模式_多线程高并发下的单例模式写法

本文详细探讨了单例模式在多线程环境下的实现方法,包括不同锁机制下的线程安全问题及其解决方案,并介绍了如何使用volatile关键字来防止指令重排序带来的问题。

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

public class Singleton {

private static Singleton instance = null;

private Singleton() {

System.out.println(Thread.currentThread().getName() + "\t 我是构造方法Singleton()");

}

public static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

public static void main(String[] args) {

/** 单线程(main线程的操作动作................)**/

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

for (int i = 1; i <= 10; i++) {

new Thread(()->{

Singleton.getInstance();

},String.valueOf(i)).start();

}

}

}

两种结果:

/** 单线程(main线程的操作动作................)**/

/** 多线程(main线程的操作动作................)**/

加上synchronized

public class Singleton {

private static Singleton instance = null;

private Singleton() {

System.out.println(Thread.currentThread().getName() + "\t 我是构造方法Singleton()");

}

public static synchronized Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

public static void main(String[] args) {

/** 单线程(main线程的操作动作................)**/

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

/** 多线程(main线程的操作动作................)**/

for (int i = 1; i <= 10; i++) {

new Thread(()->{

Singleton.getInstance();

},String.valueOf(i)).start();

}

}

}

但是在这里加synchronized太重,能保证数据一致性,但影响并非性

这里只需要控制一行代码,了解下DCL(Double Check Lock 双端检锁机制)

public class Singleton {

private static Singleton instance = null;

private Singleton() {

System.out.println(Thread.currentThread().getName() + "\t 我是构造方法Singleton()");

}

/**

* DCL(Double Check Lock 双端检锁机制)

**/

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

public static void main(String[] args) {

/** 单线程(main线程的操作动作................)**/

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

/** 多线程(main线程的操作动作................)**/

for (int i = 1; i <= 10; i++) {

new Thread(() -> {

Singleton.getInstance();

}, String.valueOf(i)).start();

}

}

}

但还存在问题,DCL(双端检锁)机制不一定线程安全,原因是有指令重排序的存在,加入volatile可以禁止指令重排,原因在于某一个线程执行到第一次检测,读取到到instance不为null时,instance的引用对象可能没有完成初始化.instance=new Singleton();可以分为三步完成,(伪代码);

memory=allocate();//1.分配对象内存空间instance(memory);//2.初始化对象instance=memory;//3.设置instance指向刚分配的内存地址,此时instance!=null;

步骤2和步骤3不存在数据依赖性关系,而且无论重排前还是重排后程序执行结果在单线程中并没有改变,因此这种重排优化是允许的.

memory=allocate();//1.分配对象内存空间instance=memory;//3.设置instance指向刚分配的内存地址,此时instance!=null;但是对象还没有初始化完成!instance(memory);//2.初始化对象

但是指令重排只会保证串行语义的执行的一致性(单线程),但并不会关心多线程间但语义一致性,所以当一条线程访问instance不为null时,由于instance实例未必已初始化完成,也就造成了线程安全问题.

(举个例子:老师为新同学张三分配了一个座位,但是张三还未到,没有就坐,其他同学去听到了这个座位是张三的,去判断不为空,但是实际张三这个真人还没有坐到座位上,发生了指令重排,我们应该考虑避免这种指令重排问题)

(张三这个真人来了,并坐到座位上,其他同学再去要微信号,手机号,才不为空)

总结下:多线程高并发环境下:单粒模式:

1):双端检索

2):volaile

public class Singleton {

//2):volaile

private static volatile Singleton instance = null;

private Singleton() {

System.out.println(Thread.currentThread().getName() + "\t 我是构造方法Singleton()");

}

/**

* DCL(Double Check Lock 双端检锁机制)

**/

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

public static void main(String[] args) {

/** 单线程(main线程的操作动作................)**/

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

// System.out.println(Singleton.getInstance()==Singleton.getInstance());

/** 多线程(main线程的操作动作................)**/

for (int i = 1; i <= 10; i++) {

new Thread(() -> {

Singleton.getInstance();

}, String.valueOf(i)).start();

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值