Java并发:线程共享变量可见性原理
0、線程安全性:線程安全性包括兩個(gè)方面,①可見性。②原子性。
0.1、線程之間的通信:線程的通信是指線程之間以何種機(jī)制來交換信息。在命令式編程中,線程之間的通信機(jī)制有兩種共享內(nèi)存和消息傳遞。
(1)在共享內(nèi)存的并發(fā)模型里,線程之間共享程序的公共狀態(tài),線程之間通過寫-讀內(nèi)存中的公共狀態(tài)來隱式進(jìn)行通信,典型的共享內(nèi)存通信方式就是通過共享對(duì)象進(jìn)行通信。
(2)在消息傳遞的并發(fā)模型里,線程之間沒有公共狀態(tài),線程之間必須通過明確的發(fā)送消息來顯式進(jìn)行通信,在java中典型的消息傳遞方式就是wait()和notify()。
?????????????????????????????Java內(nèi)存模型
1、可見性:一個(gè)線程對(duì)共享變量值得修改,能夠及時(shí)地被其他線程看到。
2、共享變量:如果一個(gè)變量在多個(gè)線程的工作內(nèi)存都存在副本,那么這個(gè)變量就是這幾個(gè)線程的共享變量。
3、線程的工作內(nèi)存:JMM抽象出的一種內(nèi)存模型。
???首先,所有的變量都是儲(chǔ)存在主內(nèi)存中的,每個(gè)線程都有自己的獨(dú)立的工作內(nèi)存,里面保存的是該線程使用到的變量的副本(它們是內(nèi)存這些變量的一份拷貝,而變量的原件是保存在主內(nèi)存的)。
???線程修改的變量的值是修改的該線程的工作內(nèi)存中的變量的副本,然后再將修改后的值刷新到主內(nèi)存中。
???此時(shí),其他線程能否及時(shí)地看到主內(nèi)存中該變量的更新的值,這時(shí)就涉及到了“可見性”問題。
???
4、JMM中有兩條規(guī)定:
???(1)線程對(duì)共享變量的所有操作都必須在自己的工作內(nèi)存中進(jìn)行,不能直接在主內(nèi)存中讀寫;
???(2)不同的線程之間不能直接訪問其他線程工作內(nèi)存的變量,線程之間變量值得傳遞只能通過主內(nèi)存來傳遞。
???
5、實(shí)現(xiàn)共享變量的可見性,必須保證兩點(diǎn):
???(1)線程修改后的共享變量值能夠及時(shí)從線程工作內(nèi)存中刷新到主內(nèi)存中;
???(2)其他線程能夠及時(shí)把共享變量的在、最新值從主內(nèi)存更新到自己的工作內(nèi)存中。
???
6、java支持的可見性實(shí)現(xiàn)的兩種方式:synchronized、volatile。
(1)synchronized能夠保證同步方法或同步代碼塊中變量的復(fù)合操作的原子性;也能保證變量的可見性。
(2)volatile不能保證變量的復(fù)合操作的原子性;只能保證變量的可見性。
7、JMM關(guān)于synchronized的兩條規(guī)定(synchronized如何實(shí)現(xiàn)內(nèi)存可見性):
(1)線程加鎖時(shí),將清空工作內(nèi)存中共享變量的值,從而使用共享變量時(shí)需要從主內(nèi)存中重新讀取最新的值。
(2)線程解鎖時(shí),必須把共享變量的最新值刷新到主內(nèi)存中。
8、synchronized線程執(zhí)行互斥代碼的六個(gè)過程:
(1)獲得互斥鎖;
(2)清空工作內(nèi)存;
(3)從主內(nèi)存中拷貝變量的最新值到工作內(nèi)存;
(4)執(zhí)行代碼;
(5)將更改后的共享變量的值刷新到主內(nèi)存;
(6)釋放互斥鎖。
9、指令重排序:重排序不會(huì)對(duì)單線程帶來內(nèi)存可見性問題。但是多線程交互時(shí),指令重排序可能會(huì)造成內(nèi)存可見性問題。
10、volatile如何實(shí)現(xiàn)內(nèi)存可見性:通過加入內(nèi)存屏障和禁止重排序來優(yōu)化實(shí)現(xiàn)的。
(1)對(duì)volatile變量執(zhí)行寫操作時(shí),會(huì)在寫操作后加入一條store屏障指令;
(2)對(duì)volatile變量執(zhí)行讀操作時(shí),會(huì)在讀操作前加入一條load屏障指令。
11、volatile如何實(shí)現(xiàn)內(nèi)存可見性:
(1)線程寫volatile變量的過程:
????1.改變線程工作內(nèi)存中volatile變量副本的值
????2.將改變后的副本的值從工作內(nèi)存刷新的主內(nèi)存
(2)線程讀volatile變量的過程:
???1.從主內(nèi)存中讀取volatile變量的最新值到線程的工作內(nèi)存中
???2.從工作內(nèi)存中讀取volatile變量的副本
???
12、volatile不能保證變量復(fù)合操作的原子性:
private int number = 0;??????????????????????????????
number++; //不是原子操作?
number++的步驟??????????????????????????????????????
1.讀取number的值??
2.將number的值加1??
3.寫入最新的number的值?????????????????????????????
????synchronized(this){??//加入synchronized,變?yōu)樵硬僮?br /> ???????number++;
????}
private volatile int number = 0;//變?yōu)関olatile變量,無法保證原子性?? ?
?
?13、volatile和synchronized的區(qū)別
(1)volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問該變量,其他線程被阻塞住。
(2)volatile僅能使用在變量級(jí)別;synchronized則可以使用在變量、方法、和類級(jí)別的。
(3)volatile僅能實(shí)現(xiàn)變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。
(4)volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞。
(5)volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化;synchronized標(biāo)記的變量可以被編譯器優(yōu)化。
?
總結(jié)
以上是生活随笔為你收集整理的Java并发:线程共享变量可见性原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 奥迪电动车 折戟在中国
- 下一篇: Java--对象内存布局