這篇文章給大家介紹如何在Java中使用volatile關(guān)鍵字,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
創(chuàng)新互聯(lián)建站是一家專業(yè)提供米林企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站設(shè)計(jì)制作、網(wǎng)站建設(shè)、HTML5建站、小程序制作等業(yè)務(wù)。10年已為米林眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。
volatile 關(guān)鍵字:當(dāng)多個(gè)線程進(jìn)行操作共享數(shù)據(jù)時(shí),可以保證內(nèi)存中的數(shù)據(jù)可見(jiàn)。 相較于 synchronized 是一種較為輕量級(jí)的同步策略。
缺點(diǎn):
1. volatile 不具備“互斥性”
2. volatile 不能保證變量的“原子性”
很多資料中是這樣介紹volatile關(guān)鍵字的:
volatile是輕量級(jí)的synchronized,它在多處理器開(kāi)發(fā)中保證了共享變量的“可見(jiàn)性”??梢?jiàn)性的意思是當(dāng)一個(gè)線程修改一個(gè)共享變量時(shí),另外一個(gè)線程能讀到這個(gè)修改的值。
文字不太好理解,通過(guò)例子來(lái)理解。
1、例子
首先看一個(gè)沒(méi)有使用volatile關(guān)鍵字例子:
package com.swnote.java; /** * volatile測(cè)試?yán)? * * @author lzj * @date [2019-04-47] */ public class VolatileTest { private boolean flag; public static void main(String[] args) { VolatileTest test = new VolatileTest(); test.test(); } public void test() { new Thread(() -> { try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } flag = true; }).start(); new Thread(() -> { while (true) { if (flag) { System.out.println("thread flag = " + flag); } } }).start(); } }
該例子中定義了一個(gè)flag共享變量,test方法里面開(kāi)啟了兩個(gè)線程,第一個(gè)線程在等待1秒中后修改共享變量flag的值為true,第二個(gè)線程通過(guò)循環(huán)判斷flag的值,當(dāng)flag的值為true時(shí),輸出內(nèi)容。
此時(shí)有兩種猜想:
執(zhí)行后,可以看到輸出內(nèi)容,即說(shuō)明第二個(gè)線程能夠感知到第一個(gè)線程對(duì)共享變量flag的修改
執(zhí)行后,沒(méi)有任務(wù)內(nèi)容,即說(shuō)明第二個(gè)線程無(wú)法感知到第一個(gè)線程對(duì)共享變量flag的修改
然后執(zhí)行結(jié)果為:
沒(méi)有任務(wù)的輸出內(nèi)容,即證明了此時(shí)這樣情況下第二個(gè)線程無(wú)法感知到第一個(gè)線程對(duì)共享變量flag的修改的
現(xiàn)在修改一下例子,即為flag變量加上volatile關(guān)鍵字,即:
private volatile boolean flag;
然后再運(yùn)行,此時(shí)結(jié)果為:
此時(shí)就有內(nèi)容輸出了,說(shuō)明加上volatile關(guān)鍵字后,第二個(gè)線程可以感知到第一個(gè)線程對(duì)共享變量flag的修改的,這就是上面概念中所說(shuō)的volatile在多處理器開(kāi)發(fā)中保證了共享變量的“可見(jiàn)性”。
2、原理
通過(guò)上面的例子證明了volatile在多處理器開(kāi)發(fā)中保證了共享變量的“可見(jiàn)性”,那它是怎么實(shí)現(xiàn)的呢?
這時(shí)就得介紹一下Java的內(nèi)存模型了,首先看如下示意圖:
Java內(nèi)存模型是如上面所示的:
共享變量存儲(chǔ)在主內(nèi)存中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存,本地內(nèi)存保存了被該線程使用到的主內(nèi)存的副本拷貝,線程對(duì)變量的所有操作都必須在自己的本地內(nèi)存中進(jìn)行,而不能直接讀寫(xiě)主內(nèi)存中的變量。
根據(jù)此理解,上述例子的在沒(méi)有加volatile時(shí)的情況是這樣的:
第一個(gè)線程從主內(nèi)存中獲取共享變量flag的值,此時(shí)值為false,將該值放到自己的本地內(nèi)存中,然后對(duì)變量進(jìn)行修改,將值改為true,此時(shí)也只是將本地內(nèi)存中flag的值改為了true,此時(shí)還沒(méi)有將值同步到主內(nèi)存中,然后第二線程也是將共享變量flag的值放到自己的本地內(nèi)存中,而此時(shí)flag的值還是為false,所以就是一直沒(méi)有內(nèi)容輸出了。
然而加上volatile關(guān)鍵字后,第一個(gè)線程對(duì)flag的修改會(huì)強(qiáng)制刷新到主內(nèi)存中去,同時(shí)還會(huì)導(dǎo)致其他線程中的本地內(nèi)存的值會(huì)無(wú)效,需要重新到主內(nèi)存獲取,這樣就保證了第一個(gè)線程對(duì)flag修改后,第二線程能夠感知到。
3、注意點(diǎn)
volatile是輕量級(jí)的synchronized,但是它是不能夠代替synchronized的,因?yàn)関olatile只能保證原子性操作的安全,對(duì)于復(fù)合操作,volatile是不能保證線程安全的。
例如:
package com.swnote.java; /** * 復(fù)合操作例子 * * @author lzj * @date [2019-04-27] */ public class StatisticTest { private volatile int num = 0; public static void main(String[] args) { StatisticTest test = new StatisticTest(); test.statistic(); } public void statistic() { for (int i = 0; i < 20; i++) { new Thread(() -> { num++; }).start(); } System.out.println("num = " + num); } }
期望的運(yùn)行結(jié)果是20,可是幾乎每次運(yùn)行結(jié)果都是不一樣的,例如有的結(jié)果為:
這是因?yàn)閚um++這個(gè)操作不是原子性的,所以即使使用了volatile關(guān)鍵字,也是不能保證安全的。
關(guān)于如何在Java中使用volatile關(guān)鍵字就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
網(wǎng)站名稱:如何在Java中使用volatile關(guān)鍵字
當(dāng)前網(wǎng)址:http://jinyejixie.com/article4/gdpcie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、做網(wǎng)站、ChatGPT、網(wǎng)站設(shè)計(jì)、網(wǎng)站改版、全網(wǎng)營(yíng)銷推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)