java併發編程的基礎

0 概述

要編寫正確的併發程序,關鍵問題在於:在訪問共享的可變狀態時需要進行的正確的管理,即原子操作和內存可見性。我們知道同步代碼塊和同步方法可以確保原子操作,但是一種常見的誤解是認爲
synchronized只能用於實現原子操作;同步其實還有另一個重要方面:內存可見性。多線程的環境下,我們希望確保一個線程修改了狀態之後對另一個線程是可見的。

1 內存可見性

加鎖機制既可以保證可見性,又可以保證原子性,而volatile修飾變量只能保證可見性。

public class NoVisibility {
    private static Test test = new Test();

    static class Test {
        private boolean ready = false;
        private int number = 0;
    }

    private static void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!test.ready) {
                    // System.out.println("number" + test.number);
                    //Thread.yield();
                }
                System.out.println("number" + test.number);
            }
        }).start();
    }

    public static void main(String[] args) throws Exception {
        run();

        //確保子線程已經啓動
        Thread.sleep(1000);
        test.number = 2;
        test.ready = true;

    }
}

可以看到如果test是volatile的話線程可以正常結束。
但是如果test不是volatile的話,線程將很大可能一直無法結束,因爲沒有volatile修飾的話test.ready一直讀的是緩存(線程中工作內存),而非主存值,除非cpu有空纔會去重新獲取test.ready的值,比如在循環體內釋放CPU執行資格或者執行一個複雜操作new個對象sysout以下什麼的。

2 先行發生原則

先行發生是java內存模型中定義的兩項操之間的偏序關係,如果說操作A先行發生於B操作,其實就是說在發生B操作之前,操作A產生的影響能被B觀察到,這個影響包括修改了內存共享變量、發送了消息、調用方法等。下面是java內存模型下一些“天然的”先行發生關係,這些先行發生關係無線任何同步器協助就已經存在,可以在編碼中直接使用。如果兩個操作之間不在此列,並且無法從下列規則推導出來的話,它們就沒有順序性保障,虛擬機就可以對它們隨意的重排序。

  • 程序次序規則(Program Order Rule):在一個線程內,按照程序代碼順序,書寫在前面的代碼先行發生於書寫後面的代碼。
  • 管程鎖定規則(Monitor Lock Rule)一個unlock 操作先行發生後面對同一個鎖lock操作。
  • volatile 變量規則(Volatile Variable Rule)對一個volatile變量的寫操作先行發生於後面這個變量的讀操作。
  • 線程啓動規則(Thread Start Rule)Thread對象的start() 方法先行發生於此線程的的每一個動作。
  • 線程終止規則(Thread Termination Rule)線程中的所有操作都先行發生於對此線程的終止檢測,可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測到線程已經終止執行。
  • 線程中斷規則(Thread Interruption Rule)對線程Interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件發生,可以通過Thread.isInterrupted()方法檢測到是否發生中斷。
  • 對象終結規則(Finalizer rule)一個對象的初始化完成,先行發生於它的finalize()方法的開始。
  • 傳遞性(Transitivity)如果操作A先行發生於操作B,操作B先行發生於操作C,那就可以得出A先行發生於操作C的結論。

深刻理解java內存模型先行發生關係,對於編寫正確的併發程序有着很大指導意義。

參考文獻
[1] 深入理解java 虛擬機(第二版),周志明著
[2]java 併發編程實戰

發佈了199 篇原創文章 · 獲贊 111 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章