全部
技术
PHP
MySQL
前端
Linux
JAVA
工具
纪念日计算器
邮记星
个人记账
笔记侠
历史上的今天
生日密码
生日书
生日密码
生日花语
博古通今
三十六计
鬼谷子
笑林广记
本草纲目
山海经
唐诗宋词
宋词300首
唐诗300首
退出
登录
注册
编辑文章
选择分类
PHP
MySQL
前端
Linux
Java
工具
选择专栏
设计模式
java基础
Angular学习
Java面试题
描述:
封面图上传 :
+
点击上传图片
#### 单例模式-单机模式 如下代码在单机模式下面没有任何问题。,但是多线程的情况下就会存在多个多个实例对象了 ```java public class TestSingle{ public TestSingle(){ System.out.println("TestSingle 构造"); } public static TestSingle single; //单例 public static TestSingle getSingleInstance(){ if(single == null){ single = new TestSingle(); } return single; } public static void main(String[] args){ System.out.println(TestSingle.getSingleInstance() == TestSingle.getSingleInstance()); //多线程下面就存在问题了 for(int i=0;i<=10;i++){ new Thread(()->{ TestSingle.getSingleInstance(); }, String.valueOf(i)).start(); } } } ``` #### 单例模式-多线程 DCL模式(double Check Lock 双端检索机制) 这种情况由于**java指令重排的优化机制**也无法完全保证单例,可能运行一千万次才出现一次。 **也就是说,在某一个线程执行第一次检测时,读取到的single不为null时,single的引用对象可能还没有完全初始化。 ** single = new TestSingle();可以分为如下三部完成(伪代码) memory = allocate();//1.分配对象内存空间 single (memory );//2.初始化对象 single = memory //3.设置single 执行刚才分配的内存地址,此时single 不为null **步骤2和步骤3不存在数据依赖关系,而且无论重排前还是重排后程序的执行结果在单线程中并没有改变,因此这种重排是允许的** 那么重排后就存在下面这种情况,先给对象分配了内存空间,那么single不为null,这个是个下一个线程判断的时候发现不为空,直接返回,于是就得到了要给没有初始化的对象。 memory = allocate();//1.分配对象内存空间single , single = memory //2.设置single 执行刚才分配的内存地址,此时single不为null,**但是对象还没有初始化完成** single (memory );//3.初始化对象 ```java public class TestSingle{ public TestSingle(){ System.out.println("TestSingle 构造"); } public static TestSingle single; //单例 public static TestSingle getSingleInstance(){ if(single == null){ synchronized (TestSingle.class){ if(single == null){ single = new TestSingle(); } } } return single; } public static void main(String[] args){ System.out.println(TestSingle.getSingleInstance() == TestSingle.getSingleInstance()); //多线程下面就存在问题了 for(int i=0;i<=10;i++){ new Thread(()->{ TestSingle.getSingleInstance(); }, String.valueOf(i)).start(); } } } ``` #### 如何解决 single 加**volatile 静止指令重排** ```java public static volatile TestSingle single; ```
保存文章