【问题标题】:why DCL use volatile ,not use final?i code run same effect为什么 DCL 使用 volatile 而不使用 final?我的代码运行相同的效果
【发布时间】:2018-10-06 14:51:42
【问题描述】:
package test1;

import java.util.Random;

public class OneInstanceService {
    // use volatile or final,them has same effect,
    // but difference volatile or final in DCL demo?
    public int i_am_has_state;

    private static OneInstanceService test;

    private OneInstanceService() {
        i_am_has_state = new Random().nextInt(200) + 1;
    }

    public static OneInstanceService getTest1() {
        if (test == null) {
            synchronized (OneInstanceService.class) {
                if (test == null) {
                    test = new OneInstanceService();
                }
            }
        }
        return test;
    }

    public static void reset() {
        test = null;
    }

}


//----------------------------------------
package test1;

import java.util.concurrent.CountDownLatch;

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        for (;;) {
            CountDownLatch latch = new CountDownLatch(1);
            CountDownLatch end = new CountDownLatch(100);
            for (int i = 0; i < 100; i++) {
                Thread t1 = new Thread() {
                    @Override
                    public void run() {
                        try {
                            latch.await();
                            OneInstanceService one = OneInstanceService.getTest1();
                            if (one.i_am_has_state == 0) {
                                System.out.println("one.i_am_has_state == 0 process exit");
                                System.exit(0);
                            }
                            end.countDown();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                t1.start();
            }
            latch.countDown();
            end.await();
            OneInstanceService.reset();
        }
    }
}

只使用:

public int i_am_has_state;

运行结果是:

System.out.println("one.i_am_has_state == 0 process exit");
System.exit(0);

但修改代码底部:

volatile public int i_am_has_state;

final public int i_am_has_state;

没有运行底部代码:

System.out.println("one.i_am_has_state == 0 process exit");
System.exit(0);

我的问题是: DCL 使用最终确定 DCL 使用 final volatile ok

所以 在 DCL final 和 volatile 的区别?

非常感谢!

【问题讨论】:

  • 我认为你搞混了。 DCL 要求 test 是可变的,除非 OneInstanceService 是线程安全的。
  • 嗨 shmosel,但我也测试了最终的线程保存。final 和 volatile 它们没有重新排序效果?
  • @Gaohongyan 过马路不用看左右,也不会被车撞到。这并不意味着它是安全的。
  • 你很困惑。这里的 DCL 与i_am_has_state 完全无关。它使用test 变量。

标签: java multithreading thread-safety final volatile


【解决方案1】:

final 和 volatile 不能同时使用,因为它们是故意相反的。

你有一个静态字段在类初始化时初始化一次:

static final Object x;
static {
    x = ...
}

或者您有一个多线程可以竞相设置的易失性静态字段(您的情况)。

复查习语必须是 volatile 才能起作用(自 jdk 1.5 起使用新的 volatile 语义)。从那时起, volatile 具有防止重新排序涉及其他变量的指令的内存屏障,这不知何故(我现在不记得那些东西了......)使丑陋的 DCL 再次工作......但并没有让它变得不那么丑陋。

(我从不需要使用 DCL;没有 DCL,同步基本上仍然没有竞争,因为 if(x==null) 非常快。)

【讨论】:

    【解决方案2】:

    谢谢大家,底部不回答。

    我修改代码:

    package test1;
    
    import java.util.Random;
    
    public class OneInstanceService {
        final public int i_am_has_state;
    
        volatile private static OneInstanceService test;
    
        private OneInstanceService() {
            i_am_has_state = new Random().nextInt(200) + 1;
        }
    
        public static OneInstanceService getTest1() {
            if (test == null) {
                synchronized (OneInstanceService.class) {
                    if (test == null) {
                        test = new OneInstanceService();
                    }
                }
            }
            return test;
        }
    
        public static void reset() {
            test = null;
        }
    
    }
    

    突然灵光一现,代码这么完美?我想我真的搞混了。

    shmosel:原谅我没有格式化代码和高亮线,非常感谢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多