簡體   English   中英

為什么沒有波動?

[英]Why no volatile?

我和同事討論了這段代碼:

public final class ShutdownHookRegistration {

/**
 * Global shutdown flag
 */
private static boolean isServerShutdown = false;

private ShutdownHookRegistration() {
    // empty
}

/**
 * Returns the current value of the global shutdown flag
 *
 * @return
 */
public static boolean isServerShutdown() {
    return isServerShutdown;
}

/**
 * Registration if shutdown hooks
 */
public static void registerShutdownHooks() {
    /**
     * 1. Shutdown hook to set the shutdown flag
     */
    Runtime.getRuntime().addShutdownHook(setGlobalShutdownFlag());
}

/**
 * Sets the global static is shutdown flag which can be checked by other processes.
 *
 * @return
 */
private static Thread setGlobalShutdownFlag() {
    return new Thread() {

        @Override
        public void run() {
            isServerShutdown = true;
            System.out.println(Thread.currentThread().getName() + ":shutdown set");
        }
    };
}

public static void main(String[] args) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + " Flag set:" + ShutdownHookRegistration.isServerShutdown);
    Thread t1 = ShutdownHookRegistration.setGlobalShutdownFlag();
    Thread t2 = new Thread() {

        public void run() {
            while (!ShutdownHookRegistration.isServerShutdown) {
                System.out.println(Thread.currentThread().getName() + " Flag set:" + ShutdownHookRegistration.isServerShutdown);
            }
        }
    };
    t2.start();
    t1.start();
}

輸出:

Thread-1 Flag set:false
Thread-1 Flag set:false
Thread-1 Flag set:false
Thread-1 Flag set:false
[..]
Thread-0:shutdown set

我認為沒有volatile這段代碼會在無限循環中運行,但不知怎的,它總會終止。

有人可以解釋為什么這里沒有必要的波動?

簡而言之,有兩個原因,你的循環有一個內存屏障,即使它沒有,它的運行時間也不足以在需要volatile的情況下進行優化/編譯。

關鍵在這里

while (!ShutdownHookRegistration.isServerShutdown) {
    System.out.println(Thread.currentThread().getName() + " Flag set:" + ShutdownHookRegistration.isServerShutdown);
}

System.out.println是synchronized ,這意味着每次迭代都有一個讀/寫屏障。

// from the java 6 source
public void println(Object x) {
    String s = String.valueOf(x);
    synchronized (this) {
        print(s);
        newLine();
    }
}

在x64 JVM中,一旦鎖定了一個對象,就會放置一個內存屏障來保護所有內存訪問。

此外,這會使代碼速度減慢10,000倍或更多,因此運行時間不足以進行編譯(並在需要使用volatile的情況下進行優化)在編譯此代碼之前,需要循環10,000次。 。

標記字段volatile ...

...確保所有線程都看到變量的一致值(第17.4節 )。

將其標記volatile並不一定意味着其他線程不會看到變化值最終 ,只是他們可能會一直看到了一段時間的舊值,因為舊值可以被緩存的線程(因為它是不volatile ) 。 但這並不意味着他們的緩存值不會在某個時候更新。 只是那可能是從另一個線程改變值時的某些移除(例如,延遲)。

如果您希望主動觀察更改,請將字段設置為volatile ,但請注意,這將影響讀取/寫入它的線程(無論這是一個問題還是另一回事)。

每個線程都獲得變量isServerShutdown的副本,JVM可以在每個未確定的時間刷新並更新該值,許多應用程序將工作,許多不,其他人將在run方法中添加另一個語句時工作...

你很幸運,如果你需要應用程序工作,你應該使用揮發性變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM