一、原子性
原子性是指乙個操作是不可中斷的,即使是多個執行緒一起執行的時候,乙個操作的開始,就不會被其他執行緒干擾、
那麼有人會想到 i++是原子操作嗎? 答案肯定不是。因為i++至少包含兩個操作,讀(從記憶體中讀出來)和行為(加上去),還有可能把加完後的資料在方法到i裡面去,
出來也是1,這兩個執行緒同時進行自己的運算變成2了,執行緒1會把2寫到i裡面去,執行緒2也會把2寫到i裡面去,最終i就是2,事實上兩個執行緒同時對i++應該變成3,這
就說明i++並不是乙個原子操作
二、有序性
計算機在真實執行你的**時,並不一定按照程式的語序來執行的
拿個圖進行分析
比如writer這個執行緒設定a=1,flag=true,reader這個執行緒去判斷我這個flag是不是為true,為true進行a+1,一般的情況下我們認為reader中flag為true,因為a+1是
先執行的所以呢i=2,可能大家都會有這樣的乙個想法,實際上這個時不一定的,如果writer和reader是在兩個執行緒中,當writer執行緒執行時可能會把順序顛倒過來,
也就是先flag=true,在a=1,這時reader執行緒去讀的時候先會看到flag=true,沒有看到a=1,這個時候a有可能等於0,reader執行緒會誤以為a=1,但事實上a=0,a=1可
能還未執行,也就是說程式執行的順序和你讀取的順序未必是一樣的
三、可見性
保證記憶體可見性就是希望確保當乙個執行緒修改了物件狀態後,其他執行緒能夠看到發生的狀態變化。在乙個單執行緒程式中,如果首先改變乙個變數的值,
再讀取該變數的值的時候,所讀取到的值就是上次寫操作寫入的值。也就是說前面操作的結果對後面的操作是肯定可見的。但是在多執行緒程式中,
如果不使用一定的同步機制,就不能保證乙個執行緒所寫入的值對另外乙個執行緒是可見的。造成這種情況的原因可能有下面幾個:
cpu 內部的快取:現在的cpu一般都擁有層次結構的幾級快取。cpu直接操作的是快取中的資料,並在需要的時候把快取中的資料與主存進行同步。
因此在某些時刻,快取中的資料與主存內的資料可能是不一致的。某個執行緒所執行的寫入操作的新值可能當前還儲存在cpu的快取中,還沒有被寫回到主存中。
這個時候,另外乙個執行緒的讀取操作讀取的就還是主存中的舊值。
cpu的指令執行順序:在某些時候,cpu可能改變指令的執行順序。這有可能導致乙個執行緒過早的看到另外乙個執行緒的寫入操作完成之後的新值。
編譯器**重排:出於效能優化的目的,編譯器可能在編譯的時候對生成的目標**進行重新排列。
事實上,在沒有同步的情況下,編譯器、處理器以及執行時都可能對操作的執行順序進行一些意想不到的調整。在缺乏足夠同步的多執行緒程式中,
要想對記憶體操作的執行順序進行判斷,幾乎無法得到正確的結論。
Java記憶體模型
1.首先,執行緒a把本地記憶體a中更新過的共享變數重新整理到主記憶體中去。2.然後,執行緒b到主記憶體中去讀取執行緒a之前已更新過的共享變數。1.共享物件對各個執行緒的可見性 2.共享物件的競爭現象 指令級並行的重排序 如果不存l在資料依賴性,處理器可以改變語句對應機器指令的執行順序。記憶體系統的重...
Java記憶體模型
int x 0 thread a int y x thread bint x 5 int y 8 int z x y 關於上面的 存在這樣關係 x和z之間存在資料依賴關係,同時y和z之間也存在資料依賴關係。為了得到正確的結果,執行指令序列時,z不能重排序到x和y的前面。但是x和y之間並沒有資料依賴關...
java記憶體模型
執行緒之間的共享變數儲存在主記憶體中,每個執行緒對應乙個私有的本地變數為共享變數的副本 指令重排序 資料依賴性 as if serial 乙個執行緒的操作必須按照程式的順序來執行 每個操作必須原子性和立刻對所有執行緒可見 允許把乙個64位的double和long型別的寫操作拆分成兩個32位操作來執行...