为什么DCL使用volatile,而不是使用final?i代码运行相同的效果

时间:2018-04-26 02:28:19

标签: java multithreading thread-safety final volatile

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最终和波动差异?

非常感谢你!

2 个答案:

答案 0 :(得分:0)

final和volatile不能合在一起,因为它们是故意相反的。

要么在初始化阶段初始化一次静态字段:

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

或者你有一个易变的静态字段,多个线程可以竞争设置(你的情况)。

对于双重检查习惯用法必须是易失性的(使用自jdk 1.5以来的新的volatile语义)。从那时起,volatile就有了内存障碍,阻止了涉及其他变量的指令的重新排序,不知何故(我现在还记不起那些东西......)让丑陋的DCL再次工作......但是没有做到不那么难看。

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

答案 1 :(得分:-1)

谢谢大家,底层没有回答。

我修改代码:

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:原谅我没有格式化代码和hightline,非常感谢。