简体   繁体   English

为什么有必要复制volatile变量而不是直接使用它?

[英]Why is it necessary to copy the volatile variable instead of using it directly?

In the book Java concurrency in practice , there is an example of customized thread (See Listing 8.7 in section 8.3.4). 实践中的Java并发性一书中,有一个自定义线程的例子(参见8.3.4节中的清单8.7)。 I pasted the code below. 我粘贴了下面的代码。 There is one thing I don't quite understand. 有一点我不太明白。 That is, the run() method copies the volatile variable debugLifecycle before using it. 也就是说, run()方法在使用之前复制volatile变量debugLifecycle And it has a comment Copy debug flag to ensure consistent value throughout . 它有一个注释复制调试标志,以确保始终如一的价值 Is there any need to copy the variable here? 有没有必要在这里复制变量? If yes, why? 如果是,为什么?

public class MyAppThread extends Thread {
    public static final String DEFAULT_NAME = "MyAppThread";
    private static volatile boolean debugLifecycle = false;

    public MyAppThread(Runnable r) {
        this(r, DEFAULT_NAME);
    }

    public MyAppThread(Runnable runnable, String name) {
        super(runnable, name + "-" + created.incrementAndGet());
        setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t,
                                          Throwable e) {
                log.log(Level.SEVERE,
                        "UNCAUGHT in thread " + t.getName(), e);
            }
        });
    }

    public void run() {
        // Question: why copy the volatile variable here?
        // Copy debug flag to ensure consistent value throughout.
        boolean debug = debugLifecycle;
        if (debug) log.log(Level.FINE, "Created " + getName());
        try {
            alive.incrementAndGet();
            super.run();
        } finally {
            alive.decrementAndGet();
            if (debug) log.log(Level.FINE, "Exiting " + getName());
        }
    }
}

The volatile keyword generally means that the variable is accessed by multiple threads. volatile关键字通常表示该变量由多个线程访问。 So you make a copy of it's state once. 所以你要复制一次状态。 If, while you are running, another thread modifies it, your copy will be unaffected. 如果在您运行时,另一个线程修改它,您的副本将不受影响。

Otherwise it might be the case that the first log.log() gets executed, but not the finally clause's log.log() . 否则可能是第一个log.log()被执行,而不是finally子句的log.log() Which could be confusing or incorrect behavior. 这可能是令人困惑或不正确的行为。

Even if debugLifecycle were not volatile in a few cases it might still be better to use a copy. 即使debugLifecycle在少数情况下是挥发它仍然可能会更好使用副本。 But volatile is a "red flag" that this variable might change at any time. 但是volatile是一个“红旗”,这个变量可能随时改变。

The volatile keyword means that it can be accessed and modified by different threads. volatile关键字意味着它可以被不同的线程访问和修改。 In java, we have no guarantee about when threads do what (until you get into more complex stuff; start with reading about semaphores and mutexes). 在java中,我们无法保证线程什么时候做什么(直到你进入更复杂的东西;从读取信号量和互斥量开始)。 So, one thread could change the value of the variable while you another thread is using it. 因此,当另一个线程正在使用它时,一个线程可以更改变量的值。 If you're in the middle of of using the variable, and the value changes, this could have a bad effect. 如果您正在使用变量,并且值发生变化,则可能会产生不良影响。 So, to prevent that, we copy the value to another variable, and that one will keep the value it had at the time of copying (while the original, volatile one might change). 因此,为了防止这种情况,我们将值复制到另一个变量,并且该值将保留复制时的值(而原始的,易变的值可能会更改)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM