volatile關鍵字

volatile關鍵字

在java2之前,Java的內存模型老是從主存(共享內存)讀取變量,而在當前的Java內存模型下,每一個線程把變量保存到本地內存中,而不是直接在主存中進行讀寫。這就可能形成一個線程在主存中修改了一個變量的值,而另外一個線程還在繼續使用它在本地內存中的值。這個問題就是變量在多線程中的可見性問題。java

要解決這個問題,就須要把變量生命爲volatile,這就指示JVM,這個變量是不穩定的,每一個線程訪問該變量,它都到主內存中讀取,並且,當變量變化時,強迫線程將變化值回寫到主存。這樣在任什麼時候刻,兩個不一樣的線程老是看到某個成員變量的同一個值,這樣也保證了變量在多線程之間的可見性。多線程

看下面一個例子:ide

public class VolatileTest extends Thread {

    private static boolean flag =true;
    @Override
    public void run() {
        System.out.println("進入run了");
        while (flag == true) {}
        System.out.println("線程被中止了!");
    }

    public static void main(String[] args) {
        VolatileTest volatileTest=new VolatileTest();
        volatileTest.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        volatileTest.flag=false;
        System.out.println("已經將isRunning賦值爲false");
    }
}

運行結果:性能

進入run了
已經將isRunning賦值爲false

能夠看到沒有「輸出線程被中止!」。線程進入了死循環。
這是由於main線程和volatileTest線程各自有一個工做線程,裏面有變量flag的拷貝,flag在這兩個線程之間不可見,即main線程修改了本身工做內存中flag的值,volatileTest線程並不知道。學習

如今咱們把flag前面加上關鍵字volatile,以下:線程

volatile private static  boolean flag =true;

輸出就變成下面:code

進入run了
已經將isRunning賦值爲false
線程被中止了!

這是由於volatile保證了變量在不一樣線程之間的可見性。內存

若是咱們不想給flag前家volatile關鍵字,也能夠經過下面的方式解決:在whiel循環裏任意加上一個輸出語句或將該線程sleep一下。資源

volatile private static  boolean flag =true;
    @Override
    public void run() {
        System.out.println("進入run了");
        while (flag == true) {
            //法1:加一個循環語句
            System.out.println("hello world");
            //法2:將當前線程sleep一下
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
        }
        System.out.println("線程被中止了!");
    }

爲何呢?
由於JVM會盡力保證變量的可見性,即使這個變量沒有加volatile關鍵字只要CPU有時間,JVM就會盡力去保證變量值的更新。這與volatile關鍵字的不一樣之處在於,volatile會強制保證變量的可見性;而不加volatile關鍵字,JVM只會盡力去保證變量的可見性,若是CPU一直有其它的事情處理,它也就不會去保證了。最開始,CPU一直處於佔用狀態,JVM不會強制CPU其主存中取變量的最新值,因此死循環。後來加入輸出語句或sleep線程,CPU就有時間去保證變量的可見性,即從主內存中去變量flag的值。同步

問題:爲何加入輸出語句,CPU就有時間了?我也在繼續學習探究。

synchronized和volatile的比較

  • volatile是保證數據在多線程之間的可見性的,而synchronized是解決資源在多線程之間的同步,同一時間,只有一個線程會獲取資源。
  • 多線程訪問volatile關鍵字不會發生阻塞,而synchronized會發生阻塞。
  • volatile只能修飾變量,synchronized能夠修飾方法,代碼塊。
  • synchronized在Java6以後引入了偏向鎖和輕量級鎖,減小得到鎖和釋放鎖帶來的性能消耗。
相關文章
相關標籤/搜索