微吼云上線多路互動(dòng)直播服務(wù) 加速多場景互動(dòng)直播落地
691
2025-04-01
并發(fā)編程系列之變量可見性問題探究
1、什么是并發(fā)中的變量可見性問題
以例子的形式看看,定義一個(gè)變量,先用static修飾,在主線程修改之后,看看在新開的子線程里能被看到?
public class Example { private static boolean flag = true; public void testss() { new Thread(new Runnable() { @Override public void run() { int i = 0; while (IfTest.flag) { i++; } System.out.println(i); } }).start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } IfTest.flag = false; System.out.println("設(shè)置flag"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
執(zhí)行,控制臺(tái)打印:
設(shè)置flag
ps:主線程對flag變量進(jìn)行修改,子線程是不能看到的,所以里面一直在循環(huán),不能打印統(tǒng)計(jì)數(shù)據(jù)值。然后怎么才能讓并發(fā)線程看見?
方式1:使用volatile關(guān)鍵字
public class Example { private static volatile boolean flag = true; public void testss() { new Thread(new Runnable() { @Override public void run() { int i = 0; while (IfTest.flag) { i++; } System.out.println(i); } }).start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } IfTest.flag = false; System.out.println("設(shè)置flag"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
控制臺(tái)打印:
設(shè)置flag
72071943
方式2:使用synchronized同步鎖
public class Example { private static boolean flag = true; public void testss() { new Thread(new Runnable() { @Override public void run() { int i = 0; while (IfTest.flag) { synchronized (this) { i++; } } System.out.println(i); } }).start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } IfTest.flag = false; System.out.println("設(shè)置flag"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
控制臺(tái)打印:
設(shè)置flag
86726163
2、什么是Java內(nèi)存模型?
解答這個(gè)問題,需要涉及到Java的內(nèi)存模型,如下所示,Java內(nèi)存模型及操作規(guī)范:
共享變量都是放在主內(nèi)存中的
每個(gè)線程都有自己的工作內(nèi)存,線程只可操作自己的工作內(nèi)存
線程要操作共享變量,需要從主內(nèi)存中讀取到工作內(nèi)存,改變值之后要從工作內(nèi)存同步到主內(nèi)存
Java內(nèi)存模型的同步交換協(xié)議,規(guī)定了8種原子操作
原子操作:不可被中斷的一個(gè)或一系列操作
lock(鎖定):將主內(nèi)存中的變量鎖定,為一個(gè)線程所獨(dú)占
unlock(解鎖):將lock加的鎖解除,其他的線程有機(jī)會(huì)訪問此變量
read(讀取):作用于主內(nèi)存變量,將主內(nèi)存中的變量值讀取到工作內(nèi)存
load(加載):作用于工作內(nèi)存,將read讀取到的值保存到工作內(nèi)存中的變量副本
use(使用):作用于工作內(nèi)存變量,將值傳遞給線程的代碼執(zhí)行引擎
assign(賦值):作用于工作內(nèi)存變量,將執(zhí)行引擎處理返回的值重新賦值給變量副本
store(存儲(chǔ)):作用于工作內(nèi)存變量,將變量副本的值傳送到主內(nèi)存中
write(寫入):作用于主內(nèi)存變量,將store傳送過來的值寫入到主內(nèi)存的共享變量中
Java內(nèi)存模型的同步交互協(xié)議,執(zhí)行上述8種原子操作時(shí)必須滿足如下規(guī)則
不允許read和load,store和write操作之一單獨(dú)出現(xiàn)。即不允許加載或同步工作到一半。
不允許一個(gè)線程丟棄它最近的assign操作,即變量在工作內(nèi)存中改變之后,必須將數(shù)據(jù)同步回主內(nèi)存
不允許一個(gè)線程無原因地(無assign操作)將數(shù)據(jù)從工作內(nèi)存同步到主內(nèi)存中。
一個(gè)新的變量可能在主內(nèi)存中誕生。
一個(gè)變量在同一個(gè)時(shí)刻只允許一條線程對其進(jìn)行l(wèi)ock操作,但lock操作可以被同一條線程重復(fù)執(zhí)行多次,多次lock之后必須要執(zhí)行相同次數(shù)unlock操作,變量才會(huì)解鎖
如果對一個(gè)對象進(jìn)行l(wèi)ock操作,那么會(huì)清空工作內(nèi)存變量中的值,在執(zhí)行引擎使用這個(gè)變量前,需要重新執(zhí)行l(wèi)oad或assign操作初始變量的值
如果一個(gè)對象事先沒有被lock,就不允許對其進(jìn)行unlock操作,也不允許去unlock一個(gè)被其他線程鎖住的變量。
對一個(gè)變量執(zhí)行unlock操作之前,必須將此變量同步回主內(nèi)存中(執(zhí)行store、write)
Java內(nèi)存模型的同步協(xié)議,操作規(guī)范
將一個(gè)變量從主內(nèi)存復(fù)制到工作內(nèi)存要順序執(zhí)行read、load操作;要將變量從工作內(nèi)存同步回主內(nèi)存要用store、write操作。只要求順序執(zhí)行,不一定是連續(xù)執(zhí)行
圖引用網(wǎng)上資料:
3、保證變量可見性的方法
final變量
synchronized
volatile修飾
4、Synchronized怎么做到可見性
synchronized語義規(guī)范:
進(jìn)入同步塊前,先清空工作內(nèi)存中的共享變量,從主內(nèi)存加載
解鎖前,必須將修改的共享變量同步回主內(nèi)存
synchronized是如何做到線程安全的?
鎖機(jī)制保護(hù)共享資源,只有獲得鎖的線程才能操作共享資源
synchronized語義規(guī)范保證了修改共享資源后,會(huì)同步回主內(nèi)存,就做到了線程安全
5、volatile關(guān)鍵字解密
volatile語義規(guī)范:
使用volatile變量時(shí),必須重新從主內(nèi)存加載到工作內(nèi)存,并且read、load是連續(xù)的
修改volatile變量后,必須馬上同步回主內(nèi)存,并且store、write是連續(xù)的
volatile可以做到線程安全?
不能,因?yàn)関olatile沒有鎖機(jī)制,線程是可以并發(fā)操作共享資源的
volatile相對synchronized有什么優(yōu)點(diǎn)?
使用volatile比synchronized簡單
volatile性能比synchronized好
volatile的使用場景?
volatile只能修飾成員變量
在多線程并發(fā)的場景才使用
volatile支持并發(fā)編程三大特效?
并發(fā)編程三大特效:原子性、有序性、可見性。
可見性:volatile和synchronized關(guān)鍵字一樣,都可以保證可見性
有序性:volatile可以保證有序性,避免指令編排的情況,依賴于操作系統(tǒng)的內(nèi)存屏障
原子行 :volatile只能保證單個(gè)操作的原子性,不能保證一系列操作的原子性,不能保證線程安全,所以說volatile不能保證原則性
Java 任務(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小時(shí)內(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小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。