目錄
原子性
如何保證原子性
可見(jiàn)性
如何保證可見(jiàn)性
有序性
如何保證有序性
Java內(nèi)存模型(JMM內(nèi)存模型)
Java內(nèi)存模型的一些關(guān)鍵概念:
主內(nèi)存與工作內(nèi)存交互協(xié)議
Java內(nèi)存模型通過(guò)以下手段來(lái)確保多線(xiàn)程程序的正確性:
鎖機(jī)制
volatile
volatile禁止指令重排序
?Happens-Before
并發(fā)三大特性
原子性、可見(jiàn)性、有序性
原子性
? ? ? ? 原子性是指一個(gè)操作是不可中斷的。一個(gè)原子操作是一個(gè)不可分割的整體,要么全部執(zhí)行成功,要么全部不執(zhí)行。在多線(xiàn)程環(huán)境下,當(dāng)多個(gè)線(xiàn)程訪(fǎng)問(wèn)共享變量時(shí),如果其中一個(gè)線(xiàn)程在執(zhí)行某個(gè)操作,其他線(xiàn)程不能同時(shí)執(zhí)行該操作。
public class AtomicTest {
private static volatile int counter = 0;
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 10000; j++) {
//synchronized (AtomicTest.class) {
counter++;
// }
}
});
thread.start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter);
}
}
? ? ? ? 正常執(zhí)行后counter變量的值遠(yuǎn)遠(yuǎn)大于預(yù)期10000,加synchronized后counter變量為10000
如何保證原子性
? ? ? 1. 通過(guò)synchronized關(guān)鍵字保證原子性
? ? ? 2. 通過(guò) Lock鎖保證原子性
? ? ? 3. 通過(guò) CAS保證原子性
可見(jiàn)性
? ? ? ?可見(jiàn)性是指當(dāng)一個(gè)線(xiàn)程修改了共享變量的值時(shí),其他線(xiàn)程能夠立即看到這個(gè)修改。在多線(xiàn)程環(huán)境下,由于線(xiàn)程之間的緩存機(jī)制,一個(gè)線(xiàn)程對(duì)共享變量的修改可能不會(huì)立即被其他線(xiàn)程看到。
?
public class VisibilityExample {
private static boolean stop = false;
public static void main(String[] args) {
// 線(xiàn)程1:修改共享變量
Thread thread1 = new Thread(() -> {
while (!stop) {
// do something
}
System.out.println("Thread 1 finished");
});
// 線(xiàn)程2:修改共享變量
Thread thread2 = new Thread(() -> {
stop = true;
System.out.println("Thread 2 set stop to true");
});
// 啟動(dòng)線(xiàn)程1
thread1.start();
// 稍等片刻
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 啟動(dòng)線(xiàn)程2
thread2.start();
}
}
? ? ? ?在以上代碼中,兩個(gè)線(xiàn)程分別運(yùn)行,并且共享一個(gè)stop變量。線(xiàn)程1在一個(gè)循環(huán)中檢查stop變量是否為false,而線(xiàn)程2在啟動(dòng)后將stop變量設(shè)置為true。然而,由于沒(méi)有同步機(jī)制,線(xiàn)程1可能不會(huì)立即看到線(xiàn)程2對(duì)stop變量的修改,導(dǎo)致線(xiàn)程1一直在循環(huán)中無(wú)法退出。
private static volatile boolean stop = false;
通過(guò)給stop變量增加volatile修飾,即可保證可見(jiàn)性。
如何保證可見(jiàn)性
? ? ? ?通過(guò)volatile 關(guān)鍵字保證可見(jiàn)性
? ? ? ?通過(guò)內(nèi)存屏障保證可見(jiàn)性
? ? ? ?通過(guò)synchronized 關(guān)鍵字保證可見(jiàn)性
? ? ? ?通過(guò)Lock鎖保證可見(jiàn)性
有序性
? ? ? ?有序性是指程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。在多線(xiàn)程環(huán)境下,由于指令重排序等優(yōu)化,有時(shí)候線(xiàn)程執(zhí)行的順序可能與代碼的順序不一致。
public class ReOrderTest {
private static int x = 0, y = 0;
private static int a = 0, b = 0;
public static void main(String[] args) throws InterruptedException {
int i=0;
while (true) {
i++;
x = 0;
y = 0;
a = 0;
b = 0;
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
//用于調(diào)整兩個(gè)線(xiàn)程的執(zhí)行順序
shortWait(20000);
a = 1;
x = b;
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
b = 1;
y = a;
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("第" + i + "次(" + x + "," + y + ")");
if (x==0&&y==0){
break;
}
}
}
public static void shortWait(long interval){
long start = System.nanoTime();
long end;
do{
end = System.nanoTime();
}while(start + interval >= end);
}
}
執(zhí)行結(jié)果:x,y出現(xiàn)了0,0的結(jié)果,程序終止。出現(xiàn)這種結(jié)果有可能是重排序?qū)е碌摹?/p>
如何保證有序性
? ? ? ?通過(guò)volatile 關(guān)鍵字保證有序性
? ? ? ?通過(guò)內(nèi)存屏障保證有序性?
? ? ? ?通過(guò)synchronized關(guān)鍵字保證有序性
? ? ? ?通過(guò)Lock鎖保證有序性
Java內(nèi)存模型(JMM內(nèi)存模型)
? ? ? ?Java內(nèi)存模型(Java Memory Model,JMM)是Java程序中多線(xiàn)程并發(fā)訪(fǎng)問(wèn)共享變量時(shí),對(duì)內(nèi)存操作行為的一種規(guī)范。它定義了在多線(xiàn)程環(huán)境中,線(xiàn)程如何與主內(nèi)存和工作內(nèi)存交互,以確保并發(fā)程序的正確性。
? ? ? ? ? ? ??
Java內(nèi)存模型的一些關(guān)鍵概念:
1. 主內(nèi)存(Main Memory): 主內(nèi)存是所有線(xiàn)程共享的內(nèi)存區(qū)域,包含所有的共享變量。所有的線(xiàn)程都可以訪(fǎng)問(wèn)主內(nèi)存。
2. 工作內(nèi)存(Working Memory): 每個(gè)線(xiàn)程有自己的工作內(nèi)存,存儲(chǔ)了該線(xiàn)程使用到的變量的副本。線(xiàn)程對(duì)變量的所有操作都在工作內(nèi)存中進(jìn)行,不直接讀寫(xiě)主內(nèi)存。
3. 共享變量: 多個(gè)線(xiàn)程之間可以共享的變量,例如類(lèi)的靜態(tài)變量或?qū)嵗兞俊?br> 4. 原子性(Atomicity): 單個(gè)的讀/寫(xiě)操作是原子的,即要么完成,要么不開(kāi)始。
5. 可見(jiàn)性(Visibility): 當(dāng)一個(gè)線(xiàn)程修改了共享變量的值,其他線(xiàn)程應(yīng)該能夠立即看到這個(gè)變化。
6. 有序性(Ordering): 程序執(zhí)行的順序與代碼中的順序一致。
主內(nèi)存與工作內(nèi)存交互協(xié)議
從工 作內(nèi)存同步到主內(nèi)存之間的實(shí)現(xiàn)細(xì)節(jié),Java內(nèi)存模型定義了以下八種原子操作來(lái)完成:
lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)識(shí)為一條線(xiàn)程獨(dú)占狀態(tài)。
unlock(解鎖):作用于主內(nèi)存變量,把一個(gè)處于鎖定狀態(tài)的變量釋放出來(lái),釋放后的變量才可以被其他線(xiàn)程鎖 定。
read(讀取):作用于主內(nèi)存變量,把一個(gè)變量值從主內(nèi)存?zhèn)鬏數(shù)骄€(xiàn)程的工作內(nèi)存中,以便隨后的load動(dòng)作使用
load(載入):作用于工作內(nèi)存的變量,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中。
use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量值傳遞給執(zhí)行引擎,每當(dāng)虛擬機(jī)遇到一個(gè)需要 使用變量的值的字節(jié)碼指令時(shí)將會(huì)執(zhí)行這個(gè)操作。
assign(賦值):作用于工作內(nèi)存的變量,它把一個(gè)從執(zhí)行引擎接收到的值賦值給工作內(nèi)存的變量,每當(dāng)虛擬機(jī) 遇到一個(gè)給變量賦值的字節(jié)碼指令時(shí)執(zhí)行這個(gè)操作。
store(存儲(chǔ)):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量的值傳送到主內(nèi)存中,以便隨后的write的操 作。
write(寫(xiě)入):作用于主內(nèi)存的變量,它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存的變量中。
Java內(nèi)存模型通過(guò)以下手段來(lái)確保多線(xiàn)程程序的正確性:
1. 鎖機(jī)制: 使用synchronized關(guān)鍵字或顯式鎖來(lái)保護(hù)共享數(shù)據(jù),確保在同一時(shí)刻只有一個(gè)線(xiàn)程可以訪(fǎng)問(wèn)臨界區(qū)。
2. volatile關(guān)鍵字: 用于修飾共享變量,保證可見(jiàn)性。對(duì)一個(gè)volatile變量的寫(xiě)操作將立即刷新到主內(nèi)存,而讀操作將從主內(nèi)存中加載最新的值。
3. final關(guān)鍵字: 被final修飾的字段在構(gòu)造函數(shù)結(jié)束之前就已經(jīng)對(duì)其他線(xiàn)程可見(jiàn)。
4. Happens-Before關(guān)系: JMM定義了Happens-Before的規(guī)則,確保在某個(gè)操作之前的操作對(duì)其可見(jiàn)。
鎖機(jī)制
1. 當(dāng)線(xiàn)程獲取鎖時(shí),JMM會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存置為無(wú)效。
2. 當(dāng)線(xiàn)程釋放鎖時(shí),JMM會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存中的共享變量刷新到主內(nèi)存中。
? ? ? ?synchronized關(guān)鍵字的作用是確保多個(gè)線(xiàn)程訪(fǎng)問(wèn)共享資源時(shí)的互斥性和可見(jiàn)性。在獲取鎖之前,線(xiàn)程 會(huì)將共享變量的最新值從主內(nèi)存中讀取到線(xiàn)程本地的緩存中,釋放鎖時(shí)會(huì)將修改后的共享變量的值刷 新到主內(nèi)存中,以保證可見(jiàn)性。
volatile
1. 當(dāng)寫(xiě)一個(gè)volatile變量時(shí),JMM會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存中的共享變量值刷新到主內(nèi)存。
2. 當(dāng)讀一個(gè)volatile變量時(shí),JMM會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存置為無(wú)效,線(xiàn)程接下來(lái)將從主內(nèi)存中讀取共享變量。
volatile禁止指令重排序
?Happens-Before
? ? ? ?Happens-Before是Java內(nèi)存模型(Java Memory Model,JMM)中一個(gè)重要的概念,用于規(guī)定多線(xiàn)程程序中操作之間的執(zhí)行順序和可見(jiàn)性關(guān)系。這個(gè)概念確保了在程序中對(duì)共享變量的操作是按照一定順序執(zhí)行的,以避免出現(xiàn)不確定的結(jié)果和數(shù)據(jù)競(jìng)爭(zhēng)問(wèn)題。
? ? ? ?如果操作A在操作B之前發(fā)生在之前(happens-before),那么操作A對(duì)于操作B來(lái)說(shuō),必定是可見(jiàn)的,而且操作A的效果將被操作B看到。??
Happens-Before部分關(guān)系規(guī)則:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-805601.html
1. 程序順序規(guī)則(Program Order Rule): 在一個(gè)線(xiàn)程中,操作按照程序代碼的先后順序執(zhí)行。
2. 鎖定規(guī)則(Lock Rule): 釋放鎖的操作Happens-Before于后續(xù)對(duì)同一鎖的加鎖操作。
3. volatile變量規(guī)則(Volatile Variable Rule): 對(duì)volatile變量的寫(xiě)操作Happens-Before于后續(xù)對(duì)這個(gè)變量的讀操作。
4. 傳遞性(Transitivity): 如果操作A Happens-Before于操作B,且操作B Happens-Before于操作C,那么操作A Happens-Before于操作C。
5. 線(xiàn)程啟動(dòng)規(guī)則(Thread Start Rule): 線(xiàn)程的啟動(dòng)操作Happens-Before于該線(xiàn)程的任何操作。
6. 線(xiàn)程終止規(guī)則(Thread Termination Rule): 線(xiàn)程的所有操作Happens-Before于其他線(xiàn)程檢測(cè)到該線(xiàn)程已經(jīng)終止。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-805601.html
到了這里,關(guān)于并發(fā)編程之三大特性及JMM內(nèi)存模型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!