黑马程序员技术交流社区

标题: 第一次发帖问问题,求大神戳进来 [打印本页]

作者: 黄小贝    时间: 2013-11-4 22:28
标题: 第一次发帖问问题,求大神戳进来
本帖最后由 黄小贝 于 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. }
复制代码

作者: 零下五度的水    时间: 2013-11-4 23:11
有些高深啊,我的理解是:
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:15
零下五度的水 发表于 2013-11-4 23:11
有些高深啊,我的理解是:
18.if (null == singleton) {// 检查实例,如果不存在就进入同步区块
19.synchro ...

你分析的很有道理,受教了
作者: 黄小贝    时间: 2013-11-4 23:29
然后顺便把另外一种懒汉型的多线程单例代码分享一下
用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. }
复制代码

作者: 零下五度的水    时间: 2013-11-4 23:41
话说。。我刚刚做了个卖票系统的volatile测试,发现它一如既往的跳票和重复。。。。。
然后度娘告诉我说volatile不支持非原子操作:n-- 这一类的操作都不行。。。
嗯,你这个应该是原子操作吧。。。。你这个一定要是原子操作啊。。。。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2