什么是缓存一致性问题?如何解决呢?
??點(diǎn)擊上方?好好學(xué)java?,選擇?星標(biāo)?公眾號
重磅資訊、干貨,第一時(shí)間送達(dá) 今日推薦:牛人 20000 字的 Spring Cloud 總結(jié),太硬核了~作者:MrHH 鏈接:https://www.cnblogs.com/HuiH/p/12690598.html當(dāng)程序在運(yùn)行過程中,會將運(yùn)算需要的數(shù)據(jù)從主存復(fù)制一份到CPU高速緩存中,那么CPU進(jìn)行計(jì)算時(shí)就可以從它的高速緩存讀取數(shù)據(jù)和向其中寫入數(shù)據(jù),當(dāng)運(yùn)算結(jié)束后,再將高速緩存中的數(shù)據(jù)刷新到主存當(dāng)中。舉個(gè)簡單的例子,比如下面的這段代碼:
i = i+1;
當(dāng)線程執(zhí)行這個(gè)語句時(shí),會先從主存當(dāng)中讀取i的值,然后復(fù)制一份到高速緩存當(dāng)中,然后CPU執(zhí)行指令對i指令進(jìn)行加1操作,然后將數(shù)據(jù)寫入高速緩存,最后將高速緩存中i最新的值刷新到主存當(dāng)中。
這個(gè)代碼在單線程中運(yùn)行時(shí)沒有任何問題的,但是在多線程中運(yùn)行就會有問題了。在多核CPU中,每條線程可能運(yùn)行于不同的CPU中,因此每個(gè)線程運(yùn)行時(shí)有自己的高速緩存(對單核CPU來說,其實(shí)也會出現(xiàn)這種問題,只不過是以線程調(diào)度的形式來分別執(zhí)行的)。我們以多核CPU為例。
比如同時(shí)有兩個(gè)線程執(zhí)行這段代碼,假如初始時(shí)i的值為0,那么我們希望兩個(gè)線程執(zhí)行完之后i的值變?yōu)?。但事實(shí)會是這樣嗎?
可能存在下面一種情況:初始時(shí),兩個(gè)線程分別讀取i的值存入各自所在的CPU的高速緩存當(dāng)中,然后線程1進(jìn)行加1操作,然后把i的最新值1寫入到內(nèi)存。此時(shí)線程2的高速緩存當(dāng)中i的值還是0,進(jìn)行加1操作后,i的值為1,然后線程2把i的值寫入內(nèi)存。
最終結(jié)果i的值是1,而不是2。這就是著名的緩存一致性問題。通常稱這種被多個(gè)線程訪問的變量為共享變量。
也就是說,如果一個(gè)變量在多個(gè)CPU中都存在緩存(一般在多線程編程時(shí)才會出現(xiàn)),那么就可能存在緩存不一致的問題。
為了解決緩存不一致問題,通常來說有以下2種解決方法:
1)通過在總線加LOCK,鎖的方式;
2)通過緩存一致性協(xié)議;
在早期的CPU中,是通過在總線上加LOCK鎖的形式來解決緩存不一致的問題。因?yàn)镃PU和其他部件進(jìn)行通信都是通過總線來進(jìn)行的,如果對總線加LOCK鎖的話,也就是說阻塞了其他CPU對其它部件訪問(如內(nèi)存),從而使得只能有一個(gè)CPU能使用這個(gè)變量的內(nèi)存。 比如上面例子中,如果一個(gè)線程在執(zhí)行i = i +1,如果在執(zhí)行這段代碼的過程中,在總線上發(fā)出了LOCK鎖的信號,那么只有等待這段代碼完全執(zhí)行完畢之后,其他CPU才能從變量i所在的內(nèi)存讀取變量,然后進(jìn)行相應(yīng)的操作。這樣就解決了緩存不一致的問題。
但是上面的方式會有一個(gè)問題,由于在鎖住總線期間,其他CPU無法訪問內(nèi)存,導(dǎo)致效率低下。
所以就出現(xiàn)了緩存一致性協(xié)議。該協(xié)議保證了每個(gè)緩存中使用的共享變量的副本是一致的。它的核心思想是: 當(dāng)CPU向內(nèi)存寫入數(shù)據(jù)時(shí),如果發(fā)現(xiàn)操作的變量時(shí)共享變量,即在其他CPU中也存在該變量的副本,會發(fā)出信號通知其他CPU將該變量的緩存行置為無效狀態(tài),因此當(dāng)其他CPU需要讀取這個(gè)變量時(shí),發(fā)現(xiàn)自己緩存中緩存該變量的緩存是無效的,那么它就會從內(nèi)存重新讀取。
總結(jié)
以上是生活随笔為你收集整理的什么是缓存一致性问题?如何解决呢?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 只需 5 分钟看完这篇 HTTPS,去阿
- 下一篇: 还不知道 Redis 分布式锁的背后原理