通過前面一章我們了解了synchronized是一個重量級的鎖,雖然JVM對它做了很多優(yōu)化,而下面介紹的volatile則是輕量級的synchronized。如果一個變量使用volatile,則它比使用synchronized的成本更加低,因?yàn)樗粫鹁€程上下文的切換和調(diào)度。Java語言規(guī)范對volatile的定義如下:

Java編程語言允許線程訪問共享變量,為了確保共享變量能被準(zhǔn)確和一致地更新,線程應(yīng)該確保通過排他鎖單獨(dú)獲得這個變量。

上面比較繞口,通俗點(diǎn)講就是說一個變量如果用volatile修飾了,則Java可以確保所有線程看到這個變量的值是一致的,如果某個線程對volatile修飾的共享變量進(jìn)行更新,那么其他線程可以立馬看到這個更新,這就是所謂的線程可見性。

volatile雖然看起來比較簡單,使用起來無非就是在一個變量前面加上volatile即可,但是要用好并不容易(LZ承認(rèn)我至今仍然使用不好,在使用時(shí)仍然是模棱兩可)。

內(nèi)存模型相關(guān)概念

理解volatile其實(shí)還是有點(diǎn)兒難度的,它與Java的內(nèi)存模型有關(guān),所以在理解volatile之前我們需要先了解有關(guān)Java內(nèi)存模型的概念,這里只做初步的介紹,后續(xù)LZ會詳細(xì)介紹Java內(nèi)存模型。

操作系統(tǒng)語義

計(jì)算機(jī)在運(yùn)行程序時(shí),每條指令都是在CPU中執(zhí)行的,在執(zhí)行過程中勢必會涉及到數(shù)據(jù)的讀寫。我們知道程序運(yùn)行的數(shù)據(jù)是存儲在主存中,這時(shí)就會有一個問題,讀寫主存中的數(shù)據(jù)沒有CPU中執(zhí)行指令的速度快,如果任何的交互都需要與主存打交道則會大大影響效率,所以就有了CPU高速緩存。CPU高速緩存為某個CPU獨(dú)有,只與在該CPU運(yùn)行的線程有關(guān)。

有了CPU高速緩存雖然解決了效率問題,但是它會帶來一個新的問題:數(shù)據(jù)一致性。在程序運(yùn)行中,會將運(yùn)行所需要的數(shù)據(jù)復(fù)制一份到CPU高速緩存中,在進(jìn)行運(yùn)算時(shí)CPU不再也主存打交道,而是直接從高速緩存中讀寫數(shù)據(jù),只有當(dāng)運(yùn)行結(jié)束后才會將數(shù)據(jù)刷新到主存中。舉一個簡單的例子:

網(wǎng)友評論