java重排序問題

java指令重排序

用兩個例子來講明:java

1.雙重鎖單例模式

public class Singleton {
    
    private static Singleton uniqueSingleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (null == uniqueSingleton) {//先判斷是否爲空,沒必要每次都加鎖
            synchronized (Singleton.class) {//再獲取鎖
                if (null == uniqueSingleton) {//再次判斷是否爲空,由於第二個線程獲取到鎖後,繼續執行,可是第一個線程已經初始化完成了
                    uniqueSingleton = new Singleton();//初始化對象
                }
            }
        }
        return uniqueSingleton;
    }
}

上述代碼是一個雙重鎖的單例模式實現方式,但存在隱患
咱們須要瞭解初始化對象的過程,包含的指令大體以下:
1.分配內存空間
2.初始化對象
3.將對象指向分配的內存空間
有些編譯器爲了提高效率,會將2 3的順序倒置(重排序,先將對象指向分配的內存空間再初始化),所以可能發生讀取到未初始化完成的對象
如何解決?
使用volatile關鍵字,禁止重排序編程

private volatile static Singleton uniqueSingleton;

2.多線程下的狀態判斷

public class NoVisibility{
    private static boolean ready;
    private static int number;
    
    private static class ReaderThrad extends Thread{
        public void run(){
            while(!ready){
                Thread.yield();
            }
            System.out.println(number);
        }
    }
    
    public static void main(String [] args){
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

上述代碼源自<<Java併發編程實踐>>書中
可能發生的現象:多線程

  1. 持續循環下去,ReaderThread可能永遠看不到ready的值
    Thread.yield()的意思是將當前狀態轉換爲就緒狀態,ReaderThread立刻又獲取到了執行機會,可能致使main線程永遠獲取不到執行的機會
  2. 可能會打印0
    ReaderThread可能看到了寫入ready的值,但卻沒有看到寫入number的值,由於發生了「重排序」現象,因爲number=42 ready=true不知足Happens-Before原則,所以JVM能夠對這兩個操做任意的重排序,便可能先執行ready=true再執行number=42

結語:本篇幅較短,不能深刻的將多線程中有關重排序的問題的講得透徹,若從發散思惟的角度來看來此問題,涉及到的相關知識點很是多,想深刻了解建議閱讀<<Java併發編程實踐>> <<深刻理解Java虛擬機>>併發

相關文章
相關標籤/搜索