天天看點

java關鍵詞Transient、native、volatile

Transient是出現在mybatis映射實體類的時候,實體類某屬性不需要映射的資料庫表字段的時候加上@transient标簽。主要的作用是對象序列化的時候會忽略這個屬性。

native在看法的過程沒有使用過,在看源碼的時候經常看到過用它來修飾一些方法。主要的作用在方法前加上native,代表方法是通過外部底層C實作的,調用的時候會用調用C語言方法調用。

volatile使用是在多線程開發的時候,有共享變量,使用它來就行修飾變量,注意它不能保證變量的原子性。對于讀操作時:該變量拿到的一直是主記憶體的(最新值),主要是在多線程共享變量中,某一個線程更改變量,另一個線程有可能會從緩存中讀取(優化的問題),用它可以保證變量的可見性;對于寫操作時:将目前處理器緩存行的資料寫回到系統記憶體, 這個寫回記憶體的操作會使得在其他處理器緩存了該記憶體位址無效。

為什麼volatile不能保持原子性:當兩個線程同時操作自增的時候,取值、加值、改變記憶體值,由于取值跟加值都是同一個時間點,兩者都還未送出修改值,記憶體值沒有失效,然後同時送出。

添加一段代碼驗證volatile的可見性:

public class Test implements Runnable {


    /**
     * 内部類實作static
     */
    static class ObjectA {
        private boolean flag = true;
    }

    /**
     * 嘗試不用volatile修飾變量和用volatile修飾變量的差別
     */
    private  volatile ObjectA a;


    /**
     * 構造函數
     * @param a
     */
    public Test(ObjectA a) {
        this.a = a;
    }

    /**
     * 實作線程run
     */
    @Override
    public void run() {
        while (a.flag) {
            //不做任何操作,或者極短的操作時間
        }
    }

    /**
     * 改變變量a的值,讓線程停止的功能
     */
    public void stop() {
        a.flag = false;
    }

    public static void main(String[] args) throws InterruptedException {
        //啟動線程
        Test test = new Test(new ObjectA());
        Thread t = new Thread(test);
        t.start();

        //跑一段時間
        Thread.sleep(1000);
        //停止線程
        test.stop();
        //等待子線程停止
        t.join();

    }

}
           

整個代碼邏輯是啟動一個線程,運作1秒,關閉它,當我們用volatile修飾a變量的時候,代碼是沒問題的,當變量改變的時候,線程馬上停止;如果不用volatile修飾變量a,會發現線程一直在運作,a變量明明改變值了,但是run擷取到的值一直是舊的值。