java 缓存一致性_Java多线程——CPU缓存原理和缓存一致性问题
說(shuō)起Java中的多線程,就不得不說(shuō)volatile關(guān)鍵詞volatile關(guān)鍵詞執(zhí)行修飾變量和實(shí)例變量,不能修飾方法參數(shù),局部變量和實(shí)例常量。
volatile是Java提供的一種輕量級(jí)的同步機(jī)制,在并發(fā)編程中,它是擔(dān)任了重要的角色。同synchronized相比(synchronized通常稱為重量級(jí)鎖),volatile更輕量級(jí)。
想要了解votatile的來(lái)龍去脈,就必須了解CPU緩存模型和java內(nèi)存模型,本文介紹前者。
眾所周知,計(jì)算機(jī)所有的運(yùn)算操作都是在cpu寄存器來(lái)完成的,運(yùn)算操作無(wú)非就是數(shù)據(jù)的讀取和寫(xiě)入操作,但CPU能訪問(wèn)的數(shù)據(jù)只能是計(jì)算機(jī)內(nèi)存(RAM),雖然相比于普通硬盤(pán)和固態(tài)硬盤(pán),RAM的速度遠(yuǎn)超這兩者,但比起CPU的處理速度來(lái)說(shuō),這之間的差距可達(dá)數(shù)千倍。
舉個(gè)簡(jiǎn)單的例子,隨著光纖的普遍接入,網(wǎng)絡(luò)速度大大提高,可不管下載速度如何提高,它的上限都受制于硬盤(pán)的寫(xiě)入速度,就算下載速度超過(guò)了10GB/s,可固態(tài)硬盤(pán)寫(xiě)入速度撐死也只能達(dá)到它的十分之一。
CPU也一樣,由于運(yùn)算速度和內(nèi)存訪問(wèn)速度上面的不對(duì)等,導(dǎo)致CPU資源會(huì)受到極大的限制,于是就有在CPU主存和內(nèi)存之間增加了緩存的設(shè)計(jì)。
看圖中I9 9900K的參數(shù),現(xiàn)在的緩存可以增加到3級(jí)。
在程序的運(yùn)行中,會(huì)將運(yùn)算所需要的數(shù)據(jù)復(fù)制一份到CPU緩存中,這樣CPU就可以直接對(duì)緩存中的數(shù)據(jù)進(jìn)行運(yùn)算,當(dāng)運(yùn)算結(jié)束后,將緩存中的數(shù)據(jù)刷新到內(nèi)存中,依靠這樣的方式,極大提高了CPU的吞吐量。
在提高了吞吐量的同時(shí),也出現(xiàn)了另一個(gè)問(wèn)題,緩存不一致、
試想有一段運(yùn)算操作:i++讀取i的值到cpu cache中
對(duì)i進(jìn)行加1操作
將結(jié)果保存到cpu cache中
運(yùn)算完成,將數(shù)據(jù)刷新到內(nèi)存中
這里就存在和java一樣的多線程問(wèn)題,在兩個(gè)線程同時(shí)對(duì)i進(jìn)行操作的時(shí)候,每個(gè)線程都有自己的工作內(nèi)存,變量i會(huì)在多個(gè)線程的本地內(nèi)存中都保存一個(gè)副本,假設(shè)i值為1,在同一時(shí)間的兩個(gè)線程讀取i的值保存在cpu cache中,經(jīng)過(guò)運(yùn)算后再寫(xiě)入內(nèi)存,但i再經(jīng)過(guò)兩次自增后,最后寫(xiě)入內(nèi)存的值還有可能是2。
為了解決這個(gè)問(wèn)題,通常有兩種辦法:加鎖的方式
緩存一致性協(xié)議
第一種方式是一種悲觀的方式,只有一個(gè)cpu能搶到鎖進(jìn)行運(yùn)算,而其他cpu就進(jìn)入阻塞狀態(tài)。這種方式的效率低下,所以就有了第二種方式。
緩存一致性協(xié)議的大致思想是:
如果cpu在操作數(shù)據(jù)的時(shí)候,發(fā)現(xiàn)數(shù)據(jù)是一個(gè)共享變量(其他cache也保存了副本),就進(jìn)行如下操作:讀取操作:不做任何處理,只是將cache的數(shù)據(jù)讀取到寄存器。
寫(xiě)入操作:發(fā)送一個(gè)信號(hào)通知其他cpu這個(gè)變量我已經(jīng)改過(guò)了,設(shè)置為無(wú)效變量,其他cpu在進(jìn)行操作的時(shí)候就不得不重新讀取一次數(shù)據(jù)再進(jìn)行操作。
總結(jié)
以上是生活随笔為你收集整理的java 缓存一致性_Java多线程——CPU缓存原理和缓存一致性问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 手机的天线去哪了?原来就在眼皮底下
- 下一篇: spring java配置_Spring