立刻有
全部
技术
PHP
MySQL
前端
Linux
JAVA
退出
编辑文章
选择分类
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; ```
保存文章