多線程高級講解二: volatile關鍵字

 

首先volatile關鍵字有線程安全問題。

volatile有一個專業術語:保證了可見性,不保證原子性。

 

首先不使用volatile關鍵字,看看有什麼效果 

public class NotUseVolatile implements Runnable {

    /**
     * 定義一個非volatile修飾的變量
     */
    private boolean falg = true;

    /**
     * 線程執行代碼
     */
    public void run() {
        System.out.println("子線程開始執行");
        while (falg) {

        }
        System.out.println("子線程執行結束");
    }


    /**
     * 生成get set方法
     */
    public boolean isFalg() {
        return falg;
    }

    public void setFalg(boolean falg) {
        this.falg = falg;
    }
}
public class Test {

    public static void main(String[] args) throws InterruptedException {
        NotUseVolatile not = new NotUseVolatile();
        Thread thread = new Thread(not, "不使用volatile關鍵字的線程");

        thread.start();

        /**
         * 休眠3秒: 如果不休眠,模擬不出這個效果。
         */
        Thread.sleep(3000);
        not.setFalg(false);
        System.out.println("flag值已修改爲false");
        Thread.sleep(1000);
        System.out.println("flag值爲:" + not.isFalg());


        /**
         * 打印結果:
         *
         *   子線程開始執行
         *   flag值已修改爲false
         *   flag值爲:false
         *
         * ------------------------------------
         *
         * 有沒有發現,flag的值已經修改了,但是線程依然沒有結束 ?
         *
         * 這是爲什麼呢 ?
         *
         * 這裏就要說到Java的內存模型了。
         *
         * 注意:
         * Java內存模型:屬於線程安全的一個知識點。
         * Java內存結構:屬於Jvm的內存分配問題,堆、棧、方法區等。
         *
         * 在java內存模型中,有主內存 和 線程內存兩個概念:
         * 全局變量在主內存中,當線程操作全局變量的時候,首先是把全局變量的值複製到線程內存中去,然後線程內存修改之後,再通知主內存修改數據。
         * 所以這裏的flag值有機率不會被修改。
         *
         * 但是如果我們要修改線程中的值,怎麼辦呢 ?
         * 就是再全局變量上加上volatile關鍵字,當加上了volatile關鍵字的全局變量被修改後,會去通知線程內存,最後線程內存的值也會修改爲主內存所改變的值。
         */

    }
}

 

 

使用volatile關鍵字:

public class UseVolatile implements Runnable {

    /**
     * 定義一個volatile修飾的變量:
     *
     * 注意:volatile關鍵字,只保證線程之間的可見性,但是不保證原子性(也就是說線程不安全)
     */
    private volatile boolean falg = true;

    /**
     * 線程執行代碼
     */
    public void run() {
        System.out.println("子線程開始執行");
        while (falg) {

        }
        System.out.println("子線程執行結束");
    }


    /**
     * 生成get set方法
     */
    public boolean isFalg() {
        return falg;
    }

    public void setFalg(boolean falg) {
        this.falg = falg;
    }
}
public class Test {

    public static void main(String[] args) throws InterruptedException {
        UseVolatile not = new UseVolatile();
        Thread thread = new Thread(not, "使用volatile關鍵字的線程");

        thread.start();

        /**
         * 休眠3秒
         */
        Thread.sleep(3000);
        not.setFalg(false);
        System.out.println("flag值已修改爲false");
        Thread.sleep(1000);
        System.out.println("flag值爲:" + not.isFalg());


        /**
         * 打印結果:
         *   線程開始執行
         *   flag值已修改爲false
         *   子線程執行結束
         *   flag值爲:false
         *
         * ------------------------------------
         *
         * 使用了volatile關鍵字後,就達到我們的理想效果了。
         *
         * 注意:volatile有線程安全問題。
         */

    }
}

 

 

所以 volatile的作用是:

每次線程讀取全局變量前必須先從主內存刷新最新的值。每次線程寫入後必須立即將修改的全局變量同步回主內存當中

 

 


 

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