A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黄小贝 高级黑马   /  2013-11-4 22:28  /  983 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 黄小贝 于 2013-11-4 23:35 编辑

在瞅多线程,怒查一下午资料,弄懂了 volatile的用法,然后,发现了如下问题,上代码
  1. /**
  2. * 双重检查加锁 单例模式,据说JDK1.5之后可以用  volatile 和 双重检查加速来实现单例模式
  3. * @author yellowbaby
  4. *
  5. */

  6. public class SingletonOne {
  7.         /**
  8.          *  volatile 的作用是让变量不再缓存在当前线程的本地空间,而是直接去操作main memory
  9.          *  我的问题是,这里为什么要使用 volatile?
  10.          */
  11.         private volatile static SingletonOne singleton = null;

  12.         private SingletonOne() {
  13.         }

  14.         public static SingletonOne getInstance() {
  15.                 if (null == singleton) {// 检查实例,如果不存在就进入同步区块
  16.                         synchronized (SingletonOne.class) {// 注意,只有第一次才彻底执行这里的代码
  17.                                 if (null != singleton) {
  18.                                         singleton = new SingletonOne();
  19.                                 }
  20.                         }
  21.                 }
  22.                 return singleton;
  23.         }
  24. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
To + 1 很给力!

查看全部评分

4 个回复

倒序浏览
有些高深啊,我的理解是:
18.if (null == singleton) {// 检查实例,如果不存在就进入同步区块
19.synchronized (SingletonOne.class) {// 注意,只有第一次才彻底执行这里的代码
20.if (null != singleton) {
21.singleton = new SingletonOne();
假设同时有两个线程(A和B)进入了18的if块,A进入19,B等待,A出了Syn块,B进入,B判断20

这个时候它会直接从自己的线程内存中读取singleton的值,
相似的情况是卖票系统,即使票总数加了static修饰,卖出的票编号也是跳跃性的,
相当于先从自己的线程内存中取票,每过一段时间跟主线程同步一次
如果B在判断20的时候还没有与主线程同步过,那他的判断结果仍旧为真,还会创建一次实例,
volatile保证了每条线程每次读取相关数据的时候都必须直接从主内存中读取,
可以避免B从自己线程内存读取singleton值导致的BUG
类似于卖票系统不按顺序出票的问题
回复 使用道具 举报
零下五度的水 发表于 2013-11-4 23:11
有些高深啊,我的理解是:
18.if (null == singleton) {// 检查实例,如果不存在就进入同步区块
19.synchro ...

你分析的很有道理,受教了
回复 使用道具 举报
然后顺便把另外一种懒汉型的多线程单例代码分享一下
用static来解决同步是个好办法,但是常规的使用static的写法是饿汉型的,但是如果丢在内部类里面就可以解决这个麻烦的问题了

  1. /**
  2. * 使用内部静态类来得到实例,因为只有在调用InnerSingleFactory.SINGLETON的时候才会加载SingletonTwo,所以也是懒汉型
  3. * @author yellowbaby
  4. *
  5. */
  6. public class SingletonTwo {

  7.         private volatile static SingletonTwo singleton = null;

  8.         private SingletonTwo() {
  9.         }

  10.         public static SingletonTwo getInstance() {
  11.                 if(singleton == null){
  12.                         singleton = InnerSingleFactory.SINGLETON;
  13.                 }
  14.                 return singleton;
  15.         }
  16.        
  17.         private final static class InnerSingleFactory {
  18.                 final static SingletonTwo SINGLETON = new SingletonTwo();
  19.         }
  20. }
复制代码
回复 使用道具 举报
话说。。我刚刚做了个卖票系统的volatile测试,发现它一如既往的跳票和重复。。。。。
然后度娘告诉我说volatile不支持非原子操作:n-- 这一类的操作都不行。。。
嗯,你这个应该是原子操作吧。。。。你这个一定要是原子操作啊。。。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马