1. 程式人生 > >JAVA併發程式設計:三大特性-可見性、有序性

JAVA併發程式設計:三大特性-可見性、有序性

生活

生活就是生下來,活下去。

————

在JAVA併發程式設計,如果要保證程式的執行緒安全,就要保證程式碼的原子性、可見性、有序性。
昨天聊了原子性。今天來看下可見性、有序性。


什麼是可見性?

當多個執行緒訪問同一個變數時,一個執行緒修改了一個變數的值,其他執行緒可以馬上讀取到修改後的值。

可見性問題

場景說明:
兩個執行緒共享一個變數stop.
A執行緒,當stop為false,則一直執行;為true則停止。
B執行緒,設定stop為true

public class Test {
    static  boolean stop;

    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("執行緒A執行中");
                while (!stop);
                System.out.println("執行緒A已停止");
            }
        }).start();

        Thread.sleep(10);


        new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("執行緒B執行中");
               stop = true;
               System.out.println("stop設定為true,執行緒B已停止");
           }
       }).start();
    }
}

其中一次執行結果:
執行緒A執行中
執行緒B執行中
stop設定為true,執行緒B已停止

由此見得,一個普通的變數在多執行緒環境下不具有可見性。

可見性的技術保障

1、Lock
2、synchronized
3、原子類
4、volatile

Lock和synchronized不用說,都是互斥鎖,保障了共享資源在同一時刻只有一個執行緒可以訪問,就不會出現可見性的問題。
volatile保障了一個變數修改以後馬上寫回主記憶體讓其他執行緒可以看到,具體的分析後面再說。
至於原子類為什麼也有可見性,因為他裡面的value本身也是volatile修飾的。

關於volatile的詳細解析,後面開一篇細聊。


什麼是有序性?

即程式執行的順序按照程式碼的先後順序執行。
編譯器和處理器為了提高執行的效率效能,會對執行進行重排序,指令重排序對單執行緒應用沒有影響,但是在多執行緒環境下可能會出現問題。

有序性問題

執行緒A

context = loadContext();  
inited = true; 

執行緒B


while(!inited ){  
 sleep  
}  
doSomethingwithconfig(context); 

假設執行緒A發生重排序:

inited = true; 
context = loadContext();  

在這種情況下,B執行緒可能會拿到沒有初始化的變數context。

有序性的技術保障

1、synchronized
2、lock
3、volatile(一定程度的有序性)
synchronized和lock在同一時刻只能讓一個執行緒執行同步方法,當然就是有序的了。
volatile的有序性是指寫入修改後的volatile變數這個操作必定優先於 讀取這個變數。