今天複習了下java記憶體模型,原子性,可見性,有序性。以下是概念。
什麼是原子性:
即一個操作或者多個操作 要麼全部執行并且執行的過程不會被任何因素打斷,要麼就都不執行。
一個很經典的例子就是銀行賬戶轉賬問題:
比如從賬戶A向賬戶B轉1000元,那麼必然包括2個操作:從賬戶A減去1000元,往賬戶B加上1000元。這2個操作必須要具備原子性才能保證不出現一些意外的問題。
我們操作資料也是如此,比如i = i+1;其中就包括,讀取i的值,計算i,寫入i。這行代碼在Java中是不具備原子性的,則多線程運作肯定會出問題,是以也需要我們使用同步和lock這些東西來確定這個特性了。
原子性其實就是保證資料一緻、線程安全一部分,
什麼 是 可見性
當多個線程通路同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。
若兩個線程在不同的cpu,那麼線程1改變了i的值還沒重新整理到主存,線程2又使用了i,那麼這個i值肯定還是之前的,線程1對變量的修改線程沒看到這就是可見性問題。
是有序性
程式執行的順序按照代碼的先後順序執行。
一般來說處理器為了提高程式運作效率,可能會對輸入代碼進行優化,它不保證程式中各個語句的執行先後順序同代碼中的順序一緻,但是它會保證程式最終執行結果和代碼順序執行的結果是一緻的。如下:
int a = 10; //語句1
int r = 2; //語句2
a = a + 3; //語句3
r = a*a; //語句4
則因為重排序,他還可能執行順序為 2-1-3-4,1-3-2-4
但絕不可能 2-1-4-3,因為這打破了依賴關系。
顯然重排序對單線程運作是不會有任何問題,而多線程就不一定了,是以我們在多線程程式設計時就得考慮這個問題了。
J ava記憶體模型
共享記憶體模型指的就是Java記憶體模型(簡稱JMM),
JMM決定一個線程對共享變量的寫入時 ,能 對另一個線程可見。從抽象的角度來看,JMM定義了線程和主記憶體之間的抽象關系:
線程之間的共享變量存儲在主記憶體(main memory)中,每個線程都有一個私有的本地記憶體(local memory),本地記憶體中存儲了該線程以讀/寫共享變量的副本。本地記憶體是JMM的一個抽象概念,并不真實存在。它涵蓋了緩存,寫緩沖區,寄存器以及其他的硬體和編譯器優化。
從上圖來看,線程A與線程B之間如要通信的話,必須要經曆下面2個步驟:
1. 首先,線程A把本地記憶體A中更新過的共享變量重新整理到主記憶體中去。
2. 然後,線程B到主記憶體中去讀取線程A之前已更新過的共享變量。
以下是2個對比例子:
package classForm;
public class VolatileDemo {
public static void main(String[] args) throws InterruptedException {
ThreadVolatileDemo t1 = new ThreadVolatileDemo();
t1.start();
Thread.sleep(300);
t1.isRun(false);
}
}
class ThreadVolatileDemo extends Thread{
private volatile boolean flag=true;
@Override
public void run() {
System.out.println("子線程開始運作");
while(flag){
}
System.out.println("子線程結束運作");
public void isRun(boolean flag){
this.flag = flag;
System.out.println("ThreadVolatileDemo==>"+flag);
以上總結:例子中的flag是在子線程當中,主線程更新了子線程當中的flag的值,但是實際循環當中那個flag讀取的值是存在主線程當中的,volatile的作用就是将子線程當中被更新的flag強制重新整理到主線程的flag當中,這樣其他線程通路的時候就可以讀取到主線程當中最新的那個flag值了。