<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
JMM就是Java記憶體模型(java memory model)。因為在不同的硬體生產商和不同的作業系統下,記憶體的存取有一定的差異,所以會造成相同的程式碼執行在不同的系統上會出現各種問題。所以java記憶體模型(JMM)遮蔽掉各種硬體和作業系統的記憶體存取差異,以實現讓java程式在各種平臺下都能達到一致的並行效果。
Java記憶體模型規定所有的變數都儲存在主記憶體中,包括範例變數,靜態變數,但是不包括區域性變數和方法引數。每個執行緒都有自己的工作記憶體,執行緒的工作記憶體儲存了該執行緒用到的變數和主記憶體的副本拷貝,執行緒對變數的操作都在工作記憶體中進行。執行緒不能直接讀寫主記憶體中的變數。
不同的執行緒之間也無法存取對方工作記憶體中的變數。執行緒之間變數值的傳遞均需要通過主記憶體來完成。
每個執行緒的工作記憶體都是獨立的,執行緒運算元據只能在工作記憶體中進行,然後刷回到主記憶體。這是 Java 記憶體模型定義的執行緒基本工作方式。
溫馨提醒一下,這裡有些人會把Java記憶體模型誤解為Java記憶體結構,然後答到堆,棧,GC垃圾回收,最後和麵試官想問的問題相差甚遠。實際上一般問到Java記憶體模型都是想問多執行緒,Java並行相關的問題。
這個簡單,整個Java記憶體模型實際上是圍繞著三個特徵建立起來的。分別是:原子性,可見性,有序性。這三個特徵可謂是整個Java並行的基礎。
原子性指的是一個操作是不可分割,不可中斷的,一個執行緒在執行時不會被其他執行緒干擾。
面試官拿筆寫了段程式碼,下面這幾句程式碼能保證原子性嗎?
int i = 2; int j = i; i++; i = i + 1;
第一句是基本型別賦值操作,必定是原子性操作。
第二句先讀取i的值,再賦值到j,兩步操作,不能保證原子性。
第三和第四句其實是等效的,先讀取i的值,再+1,最後賦值到i,三步操作了,不能保證原子性。
JMM只能保證基本的原子性,如果要保證一個程式碼塊的原子性,提供了monitorenter 和 moniterexit 兩個位元組碼指令,也就是 synchronized 關鍵字。因此在 synchronized 塊之間的操作都是原子性的。
可見性指當一個執行緒修改共用變數的值,其他執行緒能夠立即知道被修改了。Java是利用volatile關鍵字來提供可見性的。 當變數被volatile修飾時,這個變數被修改後會立刻重新整理到主記憶體,當其它執行緒需要讀取該變數時,會去主記憶體中讀取新值。而普通變數則不能保證這一點。
除了volatile關鍵字之外,final和synchronized也能實現可見性。
synchronized的原理是,在執行完,進入unlock之前,必須將共用變數同步到主記憶體中。
final修飾的欄位,一旦初始化完成,如果沒有物件逸出(指物件為初始化完成就可以被別的執行緒使用),那麼對於其他執行緒都是可見的。
在Java中,可以使用synchronized或者volatile保證多執行緒之間操作的有序性。實現原理有些區別:
volatile關鍵字是使用記憶體屏障達到禁止指令重排序,以保證有序性。
synchronized的原理是,一個執行緒lock之後,必須unlock後,其他執行緒才可以重新lock,使得被synchronized包住的程式碼塊在多執行緒之間是序列執行的。
記憶體互動操作有8種:
我再補充一下JMM對8種記憶體互動操作制定的規則吧:
很多並行程式設計都使用了volatile關鍵字,主要的作用包括兩點:
volatile修飾的變數,當一個執行緒改變了該變數的值,其他執行緒是立即可見的。普通變數則需要重新讀取才能獲得最新值。
volatile保證可見性的流程大概就是這個一個過程:
先說結論吧,volatile不能一定能保證執行緒安全。
怎麼證明呢,我們看下面一段程式碼的執行結果就知道了:
public class VolatileTest extends Thread { private static volatile int count = 0; public static void main(String[] args) throws Exception { Vector<Thread> threads = new Vector<>(); for (int i = 0; i < 100; i++) { VolatileTest thread = new VolatileTest(); threads.add(thread); thread.start(); } //等待子執行緒全部完成 for (Thread thread : threads) { thread.join(); } //輸出結果,正確結果應該是1000,實際卻是984 System.out.println(count);//984 } @Override public void run() { for (int i = 0; i < 10; i++) { try { //休眠500毫秒 Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } count++; } } }
為什麼volatile不能保證執行緒安全?
很簡單呀,可見性不能保證操作的原子性,前面說過了count++不是原子性操作,會當做三步,先讀取count的值,然後+1,最後賦值回去count變數。需要保證執行緒安全的話,需要使用synchronized關鍵字或者lock鎖,給count++這段程式碼上鎖:
private static synchronized void add() { count++; }
首先要講一下as-if-serial語意,不管怎麼重排序,(單執行緒)程式的執行結果不能被改變。
為了使指令更加符合CPU的執行特性,最大限度的發揮機器的效能,提高程式的執行效率,只要程式的最終結果與它順序化情況的結果相等,那麼指令的執行順序可以與程式碼邏輯順序不一致,這個過程就叫做指令的重排序。
重排序的種類分為三種,分別是:編譯器重排序,指令級並行的重排序,記憶體系統重排序。整個過程如下所示:
指令重排序在單執行緒是沒有問題的,不會影響執行結果,而且還提高了效能。但是在多執行緒的環境下就不能保證一定不會影響執行結果了。
所以在多執行緒環境下,就需要禁止指令重排序。
volatile關鍵字禁止指令重排序有兩層意思:
下面舉個例子:
private static int a;//非volatile修飾變數 private static int b;//非volatile修飾變數 private static volatile int k;//volatile修飾變數 private void hello() { a = 1; //語句1 b = 2; //語句2 k = 3; //語句3 a = 4; //語句4 b = 5; //語句5 //... }
變數a,b是非volatile修飾的變數,k則使用volatile修飾。所以語句3不能放在語句1、2前,也不能放在語句4、5後。但是語句1、2的順序是不能保證的,同理,語句4、5也不能保證順序。
並且,執行到語句3的時候,語句1,2是肯定執行完畢的,而且語句1,2的執行結果對於語句3,4,5是可見的。
首先要講一下記憶體屏障,記憶體屏障可以分為以下幾類:
在每個volatile讀操作後插入LoadLoad屏障,在讀操作後插入LoadStore屏障。
在每個volatile寫操作的前面插入一個StoreStore屏障,後面插入一個SotreLoad屏障。
大概的原理就是這樣。
要學習並行程式設計,java記憶體模型是第一站了。原子性,有序性,可見性這三大特徵幾乎貫穿了並行程式設計,可謂是基礎知識。對於後面要深入學習起到鋪墊作用。
在這篇文章中,如果面試的話,重點是Java記憶體模型(JMM)的工作方式,三大特徵,還有volatile關鍵字。為什麼喜歡問volatile關鍵字呢,因為volatile關鍵字可以扯出很多東西,比如可見性,有序性,還有記憶體屏障等等,可以一針見血地看出面試者的技術水平。
到此這篇關於Java面試必備之JMM高並行程式設計詳解的文章就介紹到這了,更多相關Java高並行程式設計內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45