4

Java concurrency in practice一书中,有一个自定义线程的例子(见 8.3.4 节的清单 8.7)。我粘贴了下面的代码。有一件事我不太明白。也就是说,该run()方法在使用 volatile 变量debugLifecycle之前对其进行复制。它有一个注释复制调试标志,以确保始终一致的值。是否需要在此处复制变量?如果是,为什么?

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());
        }
    }
}
4

2 回答 2

10

volatile关键字一般表示变量被多个线程访问。所以你复制它的状态一次。如果在您运行时,另一个线程对其进行了修改,您的副本将不受影响。

否则,可能log.log()会执行第一个,而不是 finally 子句的log.log(). 这可能是令人困惑或不正确的行为。

即使 debugLifecycle在某些情况下不是易变的,使用副本可能仍然更好。但这volatile是一个“危险信号”,这个变量可能随时改变。

于 2012-06-08T01:46:26.297 回答
0

volatile关键字意味着它可以被不同的线程访问和修改。在 java 中,我们不能保证线程什么时候做什么(直到你接触到更复杂的东西;从阅读信号量和互斥体开始)。因此,一个线程可以在另一个线程使用它时更改变量的值。如果您正在使用该变量,并且值发生了变化,这可能会产生不良影响。因此,为了防止这种情况,我们将值复制到另一个变量,并且该变量将保留它在复制时的值(而原始的易失变量可能会更改)。

于 2012-06-08T01:46:31.337 回答