java-多線程深入(一)JMM

(一)java內存區域概況

jvm運行java程序時把所管理的內存分成幾個部分:方法區、java棧、本地方法棧、java堆、pc程序計數器。

class字節碼裝載解析後,在多線程環境中,方法區和java堆數據共享,每個線程自帶pc程序計數器和java棧,棧幀中包含方法的所有狀態(局部變量、傳參、返回值、運算中間結果等)。對共享數據需要考慮多線程併發問題。

更詳細內容可參考《深入理解JVM虛擬機》


(二)計算機系統原型

1.內存和處理器速度不同,緩存的出現,導致數據不同步

多線程都有緩存備份,回寫可能會導致數據錯誤

2.處理器和編譯器對代碼和指令的優化,導致運算亂序

只要不影響運算結果,處理器可以調整代碼執行順序,多線程操作中會導致數據錯誤


(三)JMM概況

JMM(java momery model)提供了線程進行通訊時,確保互斥性和可見性。

(1)解決內存可見性問題


共享數據放主內存中,每個線程有自己的工作內存。

線程A讀取數據時,先從主內存拷貝數據到工作內存,進行運算後再從工作內存回寫到主內存,線程間無法相互訪問對方的數據,通過主內存實現通訊。

JMM可以控制指定共享數據實現內存可見性,寫入主內存時,同步更新其他線程中的變量值,如volatile變量的使用。

(2)禁止重排序

編譯器優化代碼,不改變運算結果的情況下,可以實現代碼重排序;處理器執行指令,不改變運算結果的情況下,可以實現指令重排序。

JMM可以禁止編譯器代碼重排序和處理器執行指令重排序(通過加入內層屏蔽)。

多線程併發問題代碼剖析

/**
 * 代碼重排序demo
 * 
 * @author peter_wang
 * @create-time 2015-1-8 下午3:06:02
 */
public class CodeChangeDemo {

    private static boolean isChange = false;

    private static class ChangeThread
        extends Thread {
        public void run() {
            System.out.println("ChangeThread start"); //1
            isChange = true;                          //2
        };
    };

    private static class GetChangeThread
        extends Thread {
        public void run() {
            System.out.println("GetChangeThread start");
            if (isChange) {                           //3
                isChange = false;
                System.out.println("change success");
            }
            else {
                System.out.println("change no success");
                System.exit(0);
            }
        };
    };

    /**
     * @param args
     */
    public static void main(String[] args) {
        while (true) {
            ChangeThread changeThread = new ChangeThread();
            GetChangeThread getChangeThread = new GetChangeThread();
            changeThread.start();
            getChangeThread.start();
            // 防止線程過多,等執行完上面倆線程再繼續
            while (Thread.activeCount() > 1) {

            }
        }
    }

}
運行結果:

ChangeThread start
GetChangeThread start
change success
ChangeThread start
GetChangeThread start
change success
ChangeThread start
GetChangeThread start
change no success
進程退出可能原因:

1.線程ChangeThread中代碼順序調整,1和2調換,執行順序1-3-2

2.線程ChangeThread執行完,工作內存中的isChange沒有回寫回主內存,導致3中isChange不是最新值。


參考文獻:

1.《深入理解JVM虛擬機》

2.http://ifeve.com/java-memory-model-1/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章