Java并發(fā)和線程安全的知識(shí)點(diǎn)有哪些-創(chuàng)新互聯(lián)

這篇“Java并發(fā)和線程安全的知識(shí)點(diǎn)有哪些”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java并發(fā)和線程安全的知識(shí)點(diǎn)有哪些”文章吧。

創(chuàng)新互聯(lián)公司從2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站建設(shè)、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元新賓做網(wǎng)站,已為上家服務(wù),為新賓各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18980820575

主內(nèi)存與工作內(nèi)存交互協(xié)議

JMM定義了8種基本操作來完成,主內(nèi)存、工作內(nèi)存和執(zhí)行引擎之間的交互,分別是lock、unlock、read、load、use、assign、store、write,虛擬機(jī)的實(shí)現(xiàn)向程序員保證每一種操作都是原子的,不可分割,對(duì)于double和long類型的64為變量不做保證。了解了這些,有助于幫我們理解內(nèi)存屏障。

別看有8個(gè)操作,實(shí)際上是成對(duì)定義的連貫操作。我們具體來看怎么記憶。

針對(duì)于主內(nèi)存的單獨(dú)操作lock和unlock

·lock:作用于主內(nèi)存、把變量標(biāo)示為線程獨(dú)占

·unlock:作用于主內(nèi)存、釋放鎖定狀態(tài)

主內(nèi)存到工作內(nèi)存的讀交換

·read:作用于主內(nèi)存,把主內(nèi)存變量傳遞給工作內(nèi)存

·load:作用于工作內(nèi)存,把read操作傳過來的值放入工作內(nèi)存

工作內(nèi)存到主內(nèi)存的寫交換

·store:作用于工作內(nèi)存,把工作內(nèi)存變量傳遞給主內(nèi)存

·write:作用于主內(nèi)存,把store過來的值寫入主內(nèi)存變量

工作內(nèi)存和執(zhí)行引擎的數(shù)據(jù)交換

·use:作用于工作內(nèi)存,把工作內(nèi)存變量傳遞給執(zhí)行引擎

·assign:作用于工作內(nèi)存,把執(zhí)行引擎的值賦給工作內(nèi)存變量

總體來說,工作內(nèi)存和主內(nèi)存的數(shù)據(jù)交換讀寫都是用兩組操作來完成,而執(zhí)行引擎和工作內(nèi)存的數(shù)據(jù)交換由兩個(gè)操作完成。當(dāng)然,上述的8種操作必須滿足一些規(guī)則,這里列舉一些我認(rèn)為重要的,例如:

·read和load、store和write必須同時(shí)出現(xiàn)

·對(duì)變量執(zhí)行l(wèi)ock操作,會(huì)清空工作內(nèi)存中緩存的該值,對(duì)變量執(zhí)行unlock操作,必須先把值同步回主內(nèi)存。

廢了這么大的篇幅,講我們Java程序員并不關(guān)心的數(shù)據(jù)交換細(xì)節(jié),是為了幫助我們理解后面的內(nèi)存屏障,系好安全帶,我們繼續(xù)來看一個(gè)完全錯(cuò)亂的Java微觀世界。

亂序的Java世界

在單線程的世界里,JMM向我們保證執(zhí)行的正確性,那么我們可以邏輯的認(rèn)為代碼是根據(jù)我們編寫的順序執(zhí)行。那么在多線程的世界里,站一個(gè)線程的視角看另一個(gè)線程,我們將完全看不清執(zhí)行的順序。并且也看不到對(duì)方執(zhí)行結(jié)果。請(qǐng)看下面的代碼:

Java并發(fā)和線程安全的知識(shí)點(diǎn)有哪些

假設(shè)有兩個(gè)線程A、B分別要執(zhí)行write和read方法,A先進(jìn)去執(zhí)行、B隨后執(zhí)行,先拋開a、b線程可見性問題,假設(shè)a、b對(duì)線程立即可見。最后c值是多少?可能是1,可能是2,甚至可能是0。接下來具體分析一下為什么。

站在B的視角看,它看不清a=1和b=1誰先執(zhí)行,由于指令重排序,很可能b=1先執(zhí)行

站在B線程的視角,B線程中read方法里的代碼是否會(huì)重排序呢,雖然這個(gè)方法的兩句話存在依賴關(guān)系,JMM支持不改變結(jié)果的指令重排,JMM無法預(yù)先判斷是否有其他線程在修改a的值,所以可能會(huì)重排,并且處理器會(huì)用猜測(cè)執(zhí)行來重排。

指令重排序讓線程看不清對(duì)方線程的執(zhí)行順序,也就是亂序的,那么會(huì)有哪些級(jí)別的指令重排序呢?有三種:編譯器重排序、指令級(jí)重排序、內(nèi)存級(jí)重排序。

內(nèi)存屏障

指令重排序會(huì)導(dǎo)致多線程執(zhí)行的無序,那么JMM會(huì)禁止特定類型的指令重排序,JMM通過內(nèi)存屏障來禁止某些指令重排序,那么有哪些內(nèi)存屏障呢?總共4類

·LoadLoad:前面的load會(huì)先于后面的load裝載

·StoreStore:前面的store會(huì)先于后面的store執(zhí)行,也就是保證內(nèi)存可見性

·LoadStore:前面的load先于后面的store執(zhí)行

·StoreLoad:前面的store先于后面的Load執(zhí)行

接下來分別看volatile、final、鎖,都有哪些內(nèi)存語義,加了哪些內(nèi)存屏障。

volatile

·對(duì)volatile變量的寫操作,前面插入StoreStore屏障,防止和上面的寫發(fā)生重排序;后面插入StoreLoad屏障,防止和后面的讀寫發(fā)生重排序。

·對(duì)volatile變量的讀操作,后面會(huì)插入兩個(gè)屏障,分別是LoadLoad、LoadStore,說白了就是,我是volatile變量,不管你下面的變量是讀或者寫,我都要先于你讀。

final

final本質(zhì)上定義是final域與構(gòu)造對(duì)象的引用之間的內(nèi)存屏障。

在構(gòu)造函數(shù)對(duì)final變量的寫人,與對(duì)構(gòu)造函數(shù)對(duì)象引用的讀,不能重排序,本質(zhì)上是插入了storeStore屏障,保證對(duì)象引用被讀之前,已經(jīng)對(duì)final變量進(jìn)行了寫人。這里特別注意指針逃逸。

讀含有final變量的對(duì)象的引用,與讀final變量不能指令重排序,插入loadload屏障,保證先讀到對(duì)象引用,在讀final變量的值,也就是只要對(duì)象構(gòu)造完成,并且在構(gòu)造函數(shù)中將final值寫入,另外一個(gè)線程肯定可以讀到,這是JMM的保證。

ReentrantLock中 有個(gè)private volatile int state,本質(zhì)上是用的volatile的內(nèi)存語義,這里就省略講了。

as-if-serial、happens-before

前面說這么多,指令重排序重排序,弄亂了Java程序,JMM提供volatile、final、鎖來禁止某些指令重排序,那么記住這些重排序規(guī)則并非簡(jiǎn)單的事,JMM用另外一種好記的理論來幫助程序員記憶。

as-if-serial:用通俗的話來解釋一下,單線中,程序邏輯的以我們看到的順序執(zhí)行,這里只是可以邏輯的認(rèn)為順序執(zhí)行,其實(shí)也會(huì)有不影響結(jié)果的指令重排,例如:

int i=1;int j=2;int a=i*j;

這里i=1,j=1重排不影響結(jié)果,那么實(shí)際上JMM是允許的。 有了as-if-serial,在單線程中,程序員不用擔(dān)心指令重排和內(nèi)存可見性問題。

happens-before:happens-before保證如果A、B兩個(gè)操作存在happens before關(guān)系,那么A操作的結(jié)果一定對(duì)B可見,有了可見性的保證,在加上正確的同步,就能寫出線程安全的代碼。JSR133定義了哪些天然的happens-before關(guān)系呢?請(qǐng)看下面:

·一個(gè)線程內(nèi),每個(gè)操作happens-before后面的操作

·unlock操作happens-before對(duì)這個(gè)這個(gè)鎖的lock操作

·volatile寫操作happens-before讀操作

·線程的start方法happens-before此線程的所有其他操作

·線程所有操作happens-before對(duì)此線程的終止監(jiān)測(cè),例如,A線程調(diào)用B線程的join方法,如果join返回,那么B線程的所有操作必定完成,且B線程的所有操作的數(shù)據(jù)必定對(duì)A線程可見。

·傳遞性,A happens-before B、B happens-before C,那么A happens-before C

以上就是關(guān)于“Java并發(fā)和線程安全的知識(shí)點(diǎn)有哪些”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道。

分享題目:Java并發(fā)和線程安全的知識(shí)點(diǎn)有哪些-創(chuàng)新互聯(lián)
文章鏈接:http://bm7419.com/article46/hsheg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、網(wǎng)站排名、定制網(wǎng)站、關(guān)鍵詞優(yōu)化、電子商務(wù)建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司