Java Happens-Before 原則
Happens-Before原則核心就是表達(dá)在一些條件下,前面的操作對于后面的操作是可見的。它有六個條件,或者說是六條原則。
一、線程中的順序性原則
這個最容易理解,這個原則是指在同一個線程中,按照程序的順序,前面的操作Happens-Before后面的操作。也就說在同一個線程中,前面先修改的數(shù)據(jù),對于后面的操作是可見的。下面舉例說明:
int a = 1;
if(a == 1){
}
上面代碼中第一行對變量a進(jìn)行的修改Happens-Before第二行查詢a的操作,所以第二行a == 1為true。
二、volatile變量原則
這個原則是指在對于用volatile修飾的變量,它的寫操作Happens-Before后續(xù)對它的讀操作。這個原則就是說在一個線程中先對volatile變量進(jìn)行了修改后,在另一個線程中讀取該volatile變量能夠讀到新值(因?yàn)镃PU緩存的存在,可能在一個線程中修改了普通變量,另一個線程無法感知)。當(dāng)然如果在同一個線程中,就可以直接使用原則一了。
volatile int a = 1;
// 線程A
a = 2;
// 線程B
if(a == 2){
}
上面代碼中,假設(shè)有兩個線程并發(fā)執(zhí)行,線程A先對a進(jìn)行賦值操作(第四行),然后線程B立刻讀取a(第七行),此時能夠保證讀取的a一定是2。
三、傳遞性
這個原則是指Happens-Before原則是可以傳遞的,指如果A Happens-Before B,且B Happens-Before C,那么A Happens-Before C。
volatile boolean a = false;
int b = 1;
// 線程A
b = 2;
a = true;
// 線程B
if(a){
System.out.println(b);
}
上面代碼中,線程A先對b進(jìn)行賦值,然后對a進(jìn)行賦值,然后線程B讀取a后,然后執(zhí)行打印b的值(根據(jù)原則二a一定為true),b的值一定為2。因?yàn)楦鶕?jù)原則一,對b賦值Happens-Before對a賦值,再根據(jù)原則二,對a的賦值Happens-Before對a的讀取,最后再根據(jù)原則三,對b的賦值Happens-Before對b的讀取的,所以b一定為2。
四、管程中鎖的原則
這個原則是指對同一個鎖的解鎖Happens-Before后續(xù)對這個鎖的加鎖。
int a = 1;
// 線程執(zhí)行
synchronized (this){
if(a == 1){
a = 2;
}
}
上面代碼中,線程A先對a進(jìn)行賦值,然后解鎖,線程B再加鎖后,此時讀到的a一定為2。
五、線程start原則
這條原則是關(guān)于線程啟動的。它是指主線程A啟動子線程B后,子線程B能夠看到主線程在啟動子線程B前的操作。也就是說如果線程A調(diào)用線程B的 start() 方法(即在線程A中啟動線程B),那么該start()操作 Happens-Before 于線程B中的任意操作。
int a = 1;
Thread B = new Thread(() -> {
// 讀取a
});
a = 2; // 假設(shè)能修改
B.start();
上面代碼中,線程A先對a進(jìn)行賦值,然后再啟動線程B,所以線程B如果能夠讀取a的話(當(dāng)然int類型,java中是不允許的),那么a一定為2。
六、線程join原則
這條是關(guān)于線程等待的。它是指主線程A等待子線程B完成(主線程A通過調(diào)用子線程B的join()方法實(shí)現(xiàn)),當(dāng)子線程B完成后(主線程A中join()方法返回),主線程能夠看到子線程的操作。
int a = 1;
Thread B = new Thread(() -> {
// 修改a
a = 2; // 假設(shè)能修改
});
B.start();
B.join();
// 讀取a
上面代碼中,讀到的a一定為2。也就是說線程B中的操作對于B.join()后面的操作都是可見的。
source: cnblogs.com/dwtfukgv/p/15631282.html記得點(diǎn)「贊」和「在看」↓
愛你們
