单例模式-单机模式

如下代码在单机模式下面没有任何问题。,但是多线程的情况下就会存在多个多个实例对象了

  1. public class TestSingle{
  2. public TestSingle(){
  3. System.out.println("TestSingle 构造");
  4. }
  5. public static TestSingle single;
  6. //单例
  7. public static TestSingle getSingleInstance(){
  8. if(single == null){
  9. single = new TestSingle();
  10. }
  11. return single;
  12. }
  13. public static void main(String[] args){
  14. System.out.println(TestSingle.getSingleInstance() == TestSingle.getSingleInstance());
  15. //多线程下面就存在问题了
  16. for(int i=0;i<=10;i++){
  17. new Thread(()->{
  18. TestSingle.getSingleInstance();
  19. }, String.valueOf(i)).start();
  20. }
  21. }
  22. }

单例模式-多线程 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.初始化对象

  1. public class TestSingle{
  2. public TestSingle(){
  3. System.out.println("TestSingle 构造");
  4. }
  5. public static TestSingle single;
  6. //单例
  7. public static TestSingle getSingleInstance(){
  8. if(single == null){
  9. synchronized (TestSingle.class){
  10. if(single == null){
  11. single = new TestSingle();
  12. }
  13. }
  14. }
  15. return single;
  16. }
  17. public static void main(String[] args){
  18. System.out.println(TestSingle.getSingleInstance() == TestSingle.getSingleInstance());
  19. //多线程下面就存在问题了
  20. for(int i=0;i<=10;i++){
  21. new Thread(()->{
  22. TestSingle.getSingleInstance();
  23. }, String.valueOf(i)).start();
  24. }
  25. }
  26. }

如何解决

single 加volatile 静止指令重排

  1. public static volatile TestSingle single;