Java內(nèi)存模型(七)happens-before">Java內(nèi)存模型(七)happens-before
626
2025-04-01
如果JMM中所有的有序性都只靠volatile和synchronized,那么有一些操作將會變得很繁瑣,但我們在編寫Java并發(fā)代碼時并沒有感到這一點(diǎn),這是因?yàn)镴ava語言中有一個先行發(fā)生(Happen-Before)原則
這個原則非常重要,它是判斷數(shù)據(jù)是否存在競爭,線程是否安全的主要依賴。
先行發(fā)生原則
指的是JMM中定義的兩項(xiàng)操作之間的依序關(guān)系
happens- before關(guān)系 主要用于強(qiáng)調(diào)兩個有沖突的動作之間的順序,以及定義數(shù)據(jù)爭用的發(fā)生時機(jī)
如果說操作A先行發(fā)生于操作B,就是在說發(fā)生B前,A產(chǎn)生的影響能被B觀察到,“影響”包含了修改內(nèi)存中共享變量的值、發(fā)送了消息、調(diào)用了方法等。意味著什么呢?如下例:
//線程A中執(zhí)行 i = 1; //線程B中執(zhí)行 j = i; //線程C中執(zhí)行 i = 2;
1
2
3
4
5
6
7
8
下面是JMM下一些”天然的“先行發(fā)生關(guān)系,無須任何同步器協(xié)助就已經(jīng)存在,可以在編碼中直接使用
如果兩個操作之間的關(guān)系不在此列,并且無法從下列規(guī)則推導(dǎo)出來的話,它們就沒有順序性保障,虛擬機(jī)可以對它們進(jìn)行隨意地重排序
具體的虛擬機(jī)實(shí)現(xiàn),有必要確保以下
八大原則
程序次序規(guī)則(Pragram Order Rule)
在一個線程內(nèi),按照代碼順序,書寫在前面的操作先行發(fā)生于書寫在后面的操作。準(zhǔn)確地說應(yīng)該是控制流順序而不是程序代碼順序,因?yàn)橐紤]分支、循環(huán)結(jié)構(gòu)。
對象鎖(監(jiān)視器鎖)法則(Monitor Lock Rule )
某個 管程(也叫做對象鎖,監(jiān)視器鎖) 上的unlock動作happens-before同一個管程上后續(xù)的lock動作 。這里必須強(qiáng)調(diào)的是同一個鎖,而”后面“是指時間上的先后。
volatile變量規(guī)則(Volatile Variable Rule)
對某個volatile字段的寫操作happens- before每個后續(xù)對該volatile字段的讀操作,這里的”后面“同樣指時間上的先后順序。
線程啟動規(guī)則(Thread Start Rule)
在某個線程對象 上調(diào)用start()方法happens- before該啟動了的線程中的任意動作
線程終止規(guī)則(Thread Termination Rule)
某線程中的所有操作都先行發(fā)生于對此線程的終止檢測,我們可以通過Thread.join()方法結(jié)束(任意其它線程成功從該線程對象上的join()中返回),Thread.isAlive()的返回值等作段檢測到線程已經(jīng)終止執(zhí)行。
線程中斷規(guī)則(Thread Interruption Rule)
對線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生,可以通過Thread.interrupted()方法檢測是否有中斷發(fā)生
對象終結(jié)規(guī)則(Finalizer Rule)
一個對象初始化完成(構(gòu)造方法執(zhí)行完成)先行發(fā)生于它的finalize()方法的開始
傳遞性(Transitivity)
如果操作A先行發(fā)生于操作B,操作B先行發(fā)生于操作C,那就可以得出操作A先行發(fā)生于操作C的結(jié)論
一個操作”時間上的先發(fā)生“不代表這個操作會是”先行發(fā)生“,那如果一個操作”先行發(fā)生“是否就能推導(dǎo)出這個操作必定是”時間上的先發(fā)生“呢?也是不成立的,一個典型的例子就是指令重排序
所以時間上的先后順序與先行發(fā)生原則之間基本沒有什么關(guān)系,所以衡量并發(fā)安全問題一切必須以先行發(fā)生原則為準(zhǔn)。
上面八條是原生Java滿足Happens-before關(guān)系的規(guī)則,但是我們可以對他們進(jìn)行推導(dǎo)出
其他滿足happens-before的案例
將一個元素放入一個線程安全的隊(duì)列的操作Happens-Before從隊(duì)列中取出這個元素的操作
將一個元素放入一個線程安全容器的操作Happens-Before從容器中取出這個元素的操作
在CountDownLatch上的倒數(shù)操作Happens-Before CountDownLatch#await()操作
Semaphore:release許可的操作Happens-Before acquire許可 的操作
CyclicBarrier:線程中調(diào)用 await() 之前的操作 happen-before 那些是屏障操作的一部份的操作,后者依次 happen-before 緊跟在從另一個線程中對應(yīng) await() 成功返回的操作。
Future表示的任務(wù)的所有操作Happens-Before Future#get()操作
向Executor提交一個Runnable或Callable的操作Happens-Before任務(wù)開始執(zhí)行操作
Java JVM 任務(wù)調(diào)度
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。