当前位置: 首页 > news >正文

单例模式中用volatile和synchronized来满足双重检查锁机制

为什么80%的码农都做不了架构师?>>> hot3.png

原文:https://www.cnblogs.com/damonhuang/p/5431866.html

背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的。

例子1:没有volatile修饰的uniqueInstance

复制代码

public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton(){
    }

    public static Singleton getInstance(){
        if(uniqueInstance == null){ //#1
            synchronized(Singleton.class){ //#2
                if(uniqueInstance == null){ //#3
                    uniqueInstance = new Singleton(); //#4
                    System.out.println(Thread.currentThread().getName() + ": uniqueInstance is initalized..."); //#5.1
                } else {
                    System.out.println(Thread.currentThread().getName() + ": uniqueInstance is not null now..."); //#5.2
                }
            }
        }
        return uniqueInstance;
    }
}

复制代码

复制代码

1 public class TestSingleton {
 2     public static void main(final String[] args) throws InterruptedException {
 3         for (int i = 1; i <= 100000; i++) {
 4             final Thread t1 = new Thread(new ThreadSingleton());
 5             t1.setName("thread" + i);
 6             t1.start();
 7         }
 8     }
 9 
10     public static class ThreadSingleton implements Runnable {
11         @Override
12         public void run() {
13             Singleton.getInstance();
14         }
15     }
16 }

复制代码

这里面的结果有可能会是:(没有真正重现过,太难模拟了)

1 thread2: uniqueInstance is initalized...
2 thread3: uniqueInstance is initalized...
Singleton被实例化两次了,和我们的单例模式设计期望值不一致:类永远只被实例化一次.

原因分析:
1. thread2进入#1, 这时子线程的uniqueInstance都是为空的,thread2让出CPU资源给thread3
2. thread3进入#1, 这时子线程的uniqueInstance都是为空的, thread3让出CPO资源给thread2
3. thread2会依次执行#2,#3,#4, #5.1,最终在thread2里面实例化了uniqueInstance。thread2执行完毕让出CPO资源给thread3
4. thread3接着#1跑下去,跑到#3的时候,由于#1里面拿到的uniqueInstance还是空(并没有及时从thread2里面拿到最新的),所以thread3仍然会执行#4,#5.1
5. 最后在thread2和thread3都实例化了uniqueInstance

例子2:用volatile修饰的uniqueInstance

这里就不贴重复的代码了,因为只是加多一个volatile来修饰成员变量:uniqueInstance,

但是结果却是正确的了, 其中一个可能结果:

 

thread2: uniqueInstance is initalized
thread3: uniqueInstance is not null now...

 

原因分析:

volatile(java5):可以保证多线程下的可见性;

读volatile:每当子线程某一语句要用到volatile变量时,都会从主线程重新拷贝一份,这样就保证子线程的会跟主线程的一致。

写volatile: 每当子线程某一语句要写volatile变量时,都会在读完后同步到主线程去,这样就保证主线程的变量及时更新。

1. thread2进入#1, 这时子线程的uniqueInstance都是为空的(java内存模型会从主线程拷贝一份uniqueInstance=null到子线程thread2),thread2让出CPU资源给thread3
2. thread3进入#1, 这时子线程的uniqueInstance都是为空的(java内存模型会从主线程拷贝一份uniqueInstance=null到子线程thread2), thread3让出CPO资源给thread2
3. thread2会依次执行#2,#3,#4, #5.1,最终在thread2里面实例化了uniqueInstance(由于是volatile修饰的变量,会马上同步到主线程的变量去)。thread2执行完毕让出CPO资源给thread3
4. thread3接着#1跑下去,跑到#3的时候,会又一次从主线程拷贝一份uniqueInstance!=null回来,所以thread3就直接跑到了#5.2
5. 最后在thread3不再会重复实例化uniqueInstance了

转载于:https://my.oschina.net/tingzi/blog/3016800

相关文章:

  • getName和getSimpleName方法一般使用
  • 博客迁移:https://blog.llyweb.com
  • 20141102-微信.NET-笔记
  • Java知识体系梳理
  • java 一些容易忽视的小点-数据类型和运算符篇
  • 设计模式--代理(Proxy)模式
  • 系统设计(系列二)--现上问题整理(云崩溃和服务不可用)
  • 医疗行业邮件服务器架设方案
  • Python 代码片段收藏
  • IOS--UISwitch的使用方法
  • Netty防止内存泄漏措施
  • GraphGL教程
  • 魔戒三曲,黑暗散去;人皇加冕,光明归来
  • Phpcms所有系统变量列表 Phpcms V9 文件目录结构
  • node 版本过低
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • HTTP中GET与POST的区别 99%的错误认识
  • isset在php5.6-和php7.0+的一些差异
  • jquery cookie
  • MySQL数据库运维之数据恢复
  • MySQL主从复制读写分离及奇怪的问题
  • nodejs:开发并发布一个nodejs包
  • ViewService——一种保证客户端与服务端同步的方法
  • Vue ES6 Jade Scss Webpack Gulp
  • Vue2.x学习三:事件处理生命周期钩子
  • 阿里云购买磁盘后挂载
  • 简析gRPC client 连接管理
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 如何优雅地使用 Sublime Text
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 物联网链路协议
  • 一天一个设计模式之JS实现——适配器模式
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 走向全栈之MongoDB的使用
  • Mac 上flink的安装与启动
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 回归生活:清理微信公众号
  • ###C语言程序设计-----C语言学习(3)#
  • #QT(智能家居界面-界面切换)
  • (4)事件处理——(7)简单事件(Simple events)
  • (6)设计一个TimeMap
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (区间dp) (经典例题) 石子合并
  • (转)http-server应用
  • (转)ObjectiveC 深浅拷贝学习
  • (转)可以带来幸福的一本书
  • (转)拼包函数及网络封包的异常处理(含代码)
  • (转载)跟我一起学习VIM - The Life Changing Editor