這篇“Java并發(fā)和線程安全的知識點有哪些”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java并發(fā)和線程安全的知識點有哪些”文章吧。
創(chuàng)新互聯(lián)公司是一家集網站建設,山陽企業(yè)網站建設,山陽品牌網站建設,網站定制,山陽網站建設報價,網絡營銷,網絡優(yōu)化,山陽網站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網站。
主內存與工作內存交互協(xié)議
JMM定義了8種基本操作來完成,主內存、工作內存和執(zhí)行引擎之間的交互,分別是lock、unlock、read、load、use、assign、store、write,虛擬機的實現(xiàn)向程序員保證每一種操作都是原子的,不可分割,對于double和long類型的64為變量不做保證。了解了這些,有助于幫我們理解內存屏障。
別看有8個操作,實際上是成對定義的連貫操作。我們具體來看怎么記憶。
針對于主內存的單獨操作lock和unlock
·lock:作用于主內存、把變量標示為線程獨占
·unlock:作用于主內存、釋放鎖定狀態(tài)
主內存到工作內存的讀交換
·read:作用于主內存,把主內存變量傳遞給工作內存
·load:作用于工作內存,把read操作傳過來的值放入工作內存
工作內存到主內存的寫交換
·store:作用于工作內存,把工作內存變量傳遞給主內存
·write:作用于主內存,把store過來的值寫入主內存變量
工作內存和執(zhí)行引擎的數(shù)據(jù)交換
·use:作用于工作內存,把工作內存變量傳遞給執(zhí)行引擎
·assign:作用于工作內存,把執(zhí)行引擎的值賦給工作內存變量
總體來說,工作內存和主內存的數(shù)據(jù)交換讀寫都是用兩組操作來完成,而執(zhí)行引擎和工作內存的數(shù)據(jù)交換由兩個操作完成。當然,上述的8種操作必須滿足一些規(guī)則,這里列舉一些我認為重要的,例如:
·read和load、store和write必須同時出現(xiàn)
·對變量執(zhí)行l(wèi)ock操作,會清空工作內存中緩存的該值,對變量執(zhí)行unlock操作,必須先把值同步回主內存。
廢了這么大的篇幅,講我們Java程序員并不關心的數(shù)據(jù)交換細節(jié),是為了幫助我們理解后面的內存屏障,系好安全帶,我們繼續(xù)來看一個完全錯亂的Java微觀世界。
亂序的Java世界
在單線程的世界里,JMM向我們保證執(zhí)行的正確性,那么我們可以邏輯的認為代碼是根據(jù)我們編寫的順序執(zhí)行。那么在多線程的世界里,站一個線程的視角看另一個線程,我們將完全看不清執(zhí)行的順序。并且也看不到對方執(zhí)行結果。請看下面的代碼:
假設有兩個線程A、B分別要執(zhí)行write和read方法,A先進去執(zhí)行、B隨后執(zhí)行,先拋開a、b線程可見性問題,假設a、b對線程立即可見。最后c值是多少?可能是1,可能是2,甚至可能是0。接下來具體分析一下為什么。
站在B的視角看,它看不清a=1和b=1誰先執(zhí)行,由于指令重排序,很可能b=1先執(zhí)行
站在B線程的視角,B線程中read方法里的代碼是否會重排序呢,雖然這個方法的兩句話存在依賴關系,JMM支持不改變結果的指令重排,JMM無法預先判斷是否有其他線程在修改a的值,所以可能會重排,并且處理器會用猜測執(zhí)行來重排。
指令重排序讓線程看不清對方線程的執(zhí)行順序,也就是亂序的,那么會有哪些級別的指令重排序呢?有三種:編譯器重排序、指令級重排序、內存級重排序。
內存屏障
指令重排序會導致多線程執(zhí)行的無序,那么JMM會禁止特定類型的指令重排序,JMM通過內存屏障來禁止某些指令重排序,那么有哪些內存屏障呢?總共4類
·LoadLoad:前面的load會先于后面的load裝載
·StoreStore:前面的store會先于后面的store執(zhí)行,也就是保證內存可見性
·LoadStore:前面的load先于后面的store執(zhí)行
·StoreLoad:前面的store先于后面的Load執(zhí)行
接下來分別看volatile、final、鎖,都有哪些內存語義,加了哪些內存屏障。
volatile
·對volatile變量的寫操作,前面插入StoreStore屏障,防止和上面的寫發(fā)生重排序;后面插入StoreLoad屏障,防止和后面的讀寫發(fā)生重排序。
·對volatile變量的讀操作,后面會插入兩個屏障,分別是LoadLoad、LoadStore,說白了就是,我是volatile變量,不管你下面的變量是讀或者寫,我都要先于你讀。
final
final本質上定義是final域與構造對象的引用之間的內存屏障。
在構造函數(shù)對final變量的寫人,與對構造函數(shù)對象引用的讀,不能重排序,本質上是插入了storeStore屏障,保證對象引用被讀之前,已經對final變量進行了寫人。這里特別注意指針逃逸。
讀含有final變量的對象的引用,與讀final變量不能指令重排序,插入loadload屏障,保證先讀到對象引用,在讀final變量的值,也就是只要對象構造完成,并且在構造函數(shù)中將final值寫入,另外一個線程肯定可以讀到,這是JMM的保證。
鎖
ReentrantLock中 有個private volatile int state,本質上是用的volatile的內存語義,這里就省略講了。
as-if-serial、happens-before
前面說這么多,指令重排序重排序,弄亂了Java程序,JMM提供volatile、final、鎖來禁止某些指令重排序,那么記住這些重排序規(guī)則并非簡單的事,JMM用另外一種好記的理論來幫助程序員記憶。
as-if-serial:用通俗的話來解釋一下,單線中,程序邏輯的以我們看到的順序執(zhí)行,這里只是可以邏輯的認為順序執(zhí)行,其實也會有不影響結果的指令重排,例如:
int i=1;int j=2;int a=i*j;
這里i=1,j=1重排不影響結果,那么實際上JMM是允許的。 有了as-if-serial,在單線程中,程序員不用擔心指令重排和內存可見性問題。
happens-before:happens-before保證如果A、B兩個操作存在happens before關系,那么A操作的結果一定對B可見,有了可見性的保證,在加上正確的同步,就能寫出線程安全的代碼。JSR133定義了哪些天然的happens-before關系呢?請看下面:
·一個線程內,每個操作happens-before后面的操作
·unlock操作happens-before對這個這個鎖的lock操作
·volatile寫操作happens-before讀操作
·線程的start方法happens-before此線程的所有其他操作
·線程所有操作happens-before對此線程的終止監(jiān)測,例如,A線程調用B線程的join方法,如果join返回,那么B線程的所有操作必定完成,且B線程的所有操作的數(shù)據(jù)必定對A線程可見。
·傳遞性,A happens-before B、B happens-before C,那么A happens-before C
以上就是關于“Java并發(fā)和線程安全的知識點有哪些”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享標題:Java并發(fā)和線程安全的知識點有哪些
地址分享:http://jinyejixie.com/article6/pdsoig.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供網頁設計公司、企業(yè)網站制作、網站維護、虛擬主機、網站內鏈、動態(tài)網站
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)