
先分析下線程訪問(wèn)數(shù)據(jù)的上述圖結(jié)構(gòu)
共享數(shù)據(jù)存儲(chǔ)在主內(nèi)存中,每個(gè)線程訪問(wèn)數(shù)據(jù)先把共享數(shù)據(jù)拷貝一份到各自線程的本地內(nèi)存中,線程運(yùn)行的數(shù)據(jù)其實(shí)是本地內(nèi)存中的拷貝數(shù)據(jù)。線程A對(duì)共享變量做出改變后,刷新到本地內(nèi)存,然后在某個(gè)時(shí)刻再刷新到主內(nèi)存(不是立即刷)。線程B再去訪問(wèn)該共享變量,從主內(nèi)存讀取副本到B的本地內(nèi)存。多線程通過(guò)主內(nèi)存共享變量的方式來(lái)達(dá)到數(shù)據(jù)通信。
本地內(nèi)存
本地內(nèi)存只是一個(gè)概念性的東西,實(shí)際并不存在,例如CPU高速緩存,讀寫(xiě)緩存器,寄存器,及其他硬件都屬于本地內(nèi)存的范疇
從原子性、可見(jiàn)性、有序性方面分析JMM
原子性
原子性要求同時(shí)只有一個(gè)線程操作代碼,不允許打斷,要不執(zhí)行完全,要不就不執(zhí)行。
可以通過(guò)synchronized和lock來(lái)解決
可見(jiàn)性
可見(jiàn)性即內(nèi)存可見(jiàn)。在分析上述圖片流程時(shí),線程A修改數(shù)據(jù)后,沒(méi)有立即刷新到主內(nèi)存,B線程如果在A中共享變量刷新到主內(nèi)存前去讀取,得到的數(shù)據(jù)就不是最新的。這就是可見(jiàn)性問(wèn)題??梢酝ㄟ^(guò)同步或者volatile解決
有序性
java編譯器或者處理器會(huì)對(duì)指令重排,單線程模式下處理器會(huì)保持執(zhí)行結(jié)果的一致性。例如:
class A {}
A a = new A();
創(chuàng)建對(duì)象這一步不是原子性操作,是一個(gè)復(fù)合操作:
1:collect申請(qǐng)內(nèi)存
2:完成對(duì)象初始化
3:將對(duì)象堆內(nèi)存首地址賦值給a
這三個(gè)指令在運(yùn)行時(shí)順序是不可控的。這就是在創(chuàng)建單例時(shí)要加volatile的原因,禁止指令重排。
volatile
1:對(duì)基本類(lèi)型成員變量的度和寫(xiě)操作(不是復(fù)合操作)保持原子性
2:保持?jǐn)?shù)據(jù)在線程間的可見(jiàn)性
3:在一定程度上保持有序性。主要是通過(guò)禁止指令重排來(lái)達(dá)到的。之所以說(shuō)一定程度上保持,是因?yàn)椴荒芡耆3?,禁止指令重排volatile對(duì)讀和寫(xiě)限制是不一樣的。
int i; ????????????????????????// 1
int j;???????????? ????????????// 2
int value = i + j;? ? ? ?// 3
volatile x = 2;? ? ? ? ? // 4
int max = x;? ? ? ? ? ? // 5
int index = i;? ? ? ? ? ?// 6
1)第4處是volatile的寫(xiě)操作。volatile的寫(xiě)操作與它之前的讀寫(xiě)操作是禁止重排序的,也就是說(shuō)1,2,3要發(fā)生在4執(zhí)行之前完全執(zhí)行完畢,并且對(duì)volatile及之后的指令具有可見(jiàn)性,但是6的有序性不能保證,6有可能在1或2后面。根據(jù)happen-befores原則,6一定在1后面。
2)第5處是對(duì)volatile的讀操作。volatile讀操作與它之后的讀寫(xiě)操作是禁止重排序的,也就是說(shuō)6要發(fā)生在5之后執(zhí)行。

此處是volatile寫(xiě)操作,因此就可以保證對(duì)象創(chuàng)建完全才會(huì)發(fā)生賦值操作,就避免了問(wèn)題。
這里有java內(nèi)存模型的系列文章,非常詳細(xì):
https://www.infoq.cn/article/java-memory-model-1
https://www.infoq.cn/article/java-memory-model-2
https://www.infoq.cn/article/java-memory-model-3
https://www.infoq.cn/article/java-memory-model-4
https://www.infoq.cn/article/java-memory-model-5
https://www.infoq.cn/article/java-memory-model-6
https://www.infoq.cn/article/java-memory-model-7