Java多线程编程笔记4:Java内存模型
Java內存模型
Java內存模型試圖屏蔽各種硬件和操作系統的內存訪問差異,以實現讓Java程序在各種平臺下都能達到一致的內存訪問效果。
處理器上的寄存器讀寫速度比內存快幾個數量級,為了解決這種速度矛盾,在它們之間加入了高速緩存。同時產生了緩存一致性問題,如果多個緩存共享同一塊主內存區域,多個緩存的數據可能不一致,需要協議來解決這個問題。
所有的變量存儲在主內存中,每個線程有自己的工作內存,工作內存存儲在高速緩存或寄存器中,保存了該線程使用的變量的主內存副本拷貝。線程只能直接操作工作內存中的變量,不同線程之間的變量值傳遞需要通過主內存來完成。
內存間交互
Java內存模型定義了8個操作來完成主內存和工作內存的交互操作。
- read:把一個變量的值從主內存傳輸到工作內存中
- load:在 read 之后執行,把 read 得到的值放入工作內存的變量副本中
- use:把工作內存中一個變量的值傳遞給執行引擎
- assign:把一個從執行引擎接收到的值賦給工作內存的變量
- store:把工作內存的一個變量的值傳送到主內存中
- write:在 store 之后執行,把 store 得到的值放入主內存的變量中
- lock:作用于主內存的變量
- unlock
內存模型的三大特性
1. 原子性
原子性就是指一個操作中要么全部執行成功,否則失敗。Java內存模型保證了上述的八個操作具有原子性。但是Java內存模型允許虛擬機將沒有被volatile修飾的64位數據(long,double)的讀寫操作劃分為兩次32位操作進行,因此load,store,read和write操作不具備原子性。但是JMM只保證了上述操作的原子性,像是i++這樣的操作,其實是分為獲取i,i自增以及賦值給i三步的,如果要實現這樣的原子操作就需要使用原子類實現,或者也可以使用它synchronized互斥鎖來保證操作的原子性。
2. 可見性
可見性指當一個線程修改了共享變量的值,其它線程能夠立即得知這個修改。Java內存模型是通過在變量修改后將新值同步回主內存,在變量讀取前從主內存刷新變量值來實現可見性的。
可見性的三種是實現方式:- volatile
- synchronized,對一個變量執行unlock操作之前,必須把變量值同步回主內存。
- final,被 final關鍵字修飾的字段在構造器中一旦初始化完成,并且沒有發生 this 逃逸(其它線程通過 this 引用訪問到初始化了一半的對象),那么其它線程就能看見 final 字段的值。
使用 volatile 關鍵詞修飾的變量每次讀取都會得到最新的數據,不管哪個線程對這個變量的修改都會立即刷新到主內存。但是 volatile 關鍵字不能保證操作的原子性。
synchronized和加鎖也能能保證可見性,實現原理就是在釋放鎖之前其余線程是訪問不到這個共享變量的。但是和 volatile 相比開銷較大。
3. 順序性
假設有三個語句a,b,c。在同一個線程內,操作是有序的,以a->b->c的順序執行。但是,JMM在保證最終結果和代碼順序執行結果一致的情況下,為了提高整體效率會進行指令重排。在單線程中重排不會問題,在多小縣城中,可能會有數據不一致的問題。
Java中可以使用volatile關鍵字來保證順序性,還可以用synchronized和lock來保證。
volatile 關鍵字通過添加內存屏障的方式來禁止指令重排,即重排序時不能把后面的指令放到內存屏障之前。
通過 synchronized 和 lock 來保證有序性,它保證每個時刻只有一個線程執行同步代碼,相當于是讓線程順序執行同步代碼。
JVM通過happen-before來保證順序性
除了使用volatile和synchronized保證順序性,JVM還規定了先行發生原則,讓一個操作無需控制就能先于另一個操作完成。
參考資料
- github.com/CyC2018/CS-…
- crossoverjie.top/JCSprout/#/…
總結
以上是生活随笔為你收集整理的Java多线程编程笔记4:Java内存模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小班音乐教案《妈妈我要亲亲你》反思
- 下一篇: 赵云故里在现在哪里