摘要:但在多線程環(huán)境中就可能出現(xiàn)問題如下面代碼線程語(yǔ)句語(yǔ)句線程線程中的語(yǔ)句和語(yǔ)句并沒有數(shù)據(jù)依賴關(guān)系,所以可能會(huì)進(jìn)行指令重排序,先去執(zhí)行語(yǔ)句,而這時(shí)線程會(huì)以為線程已經(jīng)執(zhí)行完而去執(zhí)行這樣就導(dǎo)致程序出錯(cuò)。
經(jīng)常會(huì)聽到volatile這個(gè)關(guān)鍵字,但沒有深入的去了解過它,今天好好的整理一下
要談volatile,我們先談?wù)勊睦洗蟾鐂ynchronized
一.synchronized
并發(fā)編程中最重要的三個(gè)特性是什么?原子性,可見性,有序性。只要有一個(gè)不能保證,就有可能導(dǎo)致程序的運(yùn)行錯(cuò)誤,我們熟知的synchronized就能保障原子性,可見性,有序性,因?yàn)閟ynchronized能保障任意一個(gè)時(shí)刻只有一個(gè)線程執(zhí)行該代碼塊,自然就不存在原子性的問題,又因?yàn)樵卺尫沛i之前會(huì)將變量的修改刷新到主存中,因此保證可見性,又因?yàn)槊恳粫r(shí)刻只有一個(gè)線程在執(zhí)行代碼,相當(dāng)于讓線程順序執(zhí)行同步代碼,所以也可以保證有序性。所以synchronized可保證原子性,可見性,有序性
二.volatile
volatile可以說是一個(gè)稍弱的同步機(jī)制,因?yàn)樗梢员U峡梢娦院陀行蛐?,不能保障原子?/p>
1.volatile可見性
先看下圖,java中所有的變量都存儲(chǔ)在主內(nèi)存區(qū),在多線程環(huán)境中,還有自己的工作內(nèi)存,線程操作變量時(shí)是從主存中拷貝變量到工作內(nèi)存操作,這樣很容易產(chǎn)生"臟讀"的問題。synchronized解決此問題的方法上面也談到了,volatile是如何保證的呢?當(dāng)一個(gè)變量被volatile修飾時(shí),它會(huì)保證每次被修改的值會(huì)被立刻更新到主存,而且當(dāng)緩存1對(duì)某個(gè)變量進(jìn)行修改時(shí),其它線程的工作內(nèi)存中的該變量的緩存行無效(反映到硬件層的話,就是CPU的L1或者L2緩存中對(duì)應(yīng)的緩存行無效),緩存2發(fā)現(xiàn)自己的變量無效后會(huì)等待緩存行對(duì)應(yīng)的主存地址被更新后從主存中讀取最新值,這樣就保證了可見性
2.volatile有序性
說到volatile的有序性就要提到指令重排序(Instruction Reorder),什么是指令重排序?這是JVM為了提高代碼的執(zhí)行效率對(duì)代碼進(jìn)行的優(yōu)化,它不能保證代碼先后順序執(zhí)行的一致,但可以保證執(zhí)行的結(jié)果和順序執(zhí)行的結(jié)構(gòu)一致。但在多線程環(huán)境中就可能出現(xiàn)問題,如下面代碼
//線程1 func1(); 語(yǔ)句1 boolean flag = true; 語(yǔ)句2 //線程2 while (!flag){ sleep(); } func2();
線程1中的語(yǔ)句1和語(yǔ)句2并沒有數(shù)據(jù)依賴關(guān)系,所以可能會(huì)進(jìn)行指令重排序,先去執(zhí)行語(yǔ)句2,而這時(shí)線程2會(huì)以為線程1已經(jīng)執(zhí)行完func1()而去執(zhí)行func2(),這樣就導(dǎo)致程序出錯(cuò)。
volatile關(guān)鍵字修飾的變量能禁止指令重排序,這樣就在一定程度上保證了有序性
應(yīng)用:
(1)狀態(tài)標(biāo)記量
//線程1 func1(); 語(yǔ)句1 boolean volatile flag = true; 語(yǔ)句2 //線程2 while (!flag){ sleep(); } func2();
這是對(duì)上面程序的改進(jìn),避免了程序出錯(cuò)
(2)單例模式中的雙重校驗(yàn)鎖
public class Singleton3 { private Singleton3(){} private static volatile Singleton3 instance = null; public static Singleton3 getInstance() { if(instance == null){ synchronized (Singleton3.class){ instance = new Singleton3(); } } return instance; } }
我們看到已經(jīng)有synchronizd來保證線程同步,為什么還需要volatile來修飾變量instance呢?
原因在 instance = new Singleton3();這句,JVM實(shí)際上對(duì)它進(jìn)行了如下操作
(1)給instance分配內(nèi)存 (2)調(diào)用Singleton3的構(gòu)造函數(shù)完成初始化成員變量 (3)將instance指向內(nèi)存分配空間
但由于JVM存在指令重排序優(yōu)化,執(zhí)行的順序可能就為1-3-2,就可能發(fā)生當(dāng)3執(zhí)行完另一個(gè)線程以為它已經(jīng)執(zhí)行完了,搶占當(dāng)前線程,這時(shí)instance非null但沒有初始化,所以另一個(gè)線程和以后的線程都會(huì)直接返回該沒有初始化的instance,從而出現(xiàn)錯(cuò)誤。當(dāng)有volatile修飾變量instance,就可以禁止指令重排序,從而避免出錯(cuò)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69079.html
摘要:前半句是指線程內(nèi)表現(xiàn)為串行的語(yǔ)義,后半句是指指令重排序現(xiàn)象和工作內(nèi)存和主內(nèi)存同步延遲現(xiàn)象。關(guān)于內(nèi)存模型的講解請(qǐng)參考死磕同步系列之。目前國(guó)內(nèi)市面上的關(guān)于內(nèi)存屏障的講解基本不會(huì)超過這三篇文章,包括相關(guān)書籍中的介紹。問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實(shí)現(xiàn)原理? (4)volatile的缺陷? 簡(jiǎn)介 volatile...
摘要:前半句是指線程內(nèi)表現(xiàn)為串行的語(yǔ)義,后半句是指指令重排序現(xiàn)象和工作內(nèi)存和主內(nèi)存同步延遲現(xiàn)象。關(guān)于內(nèi)存模型的講解請(qǐng)參考死磕同步系列之。目前國(guó)內(nèi)市面上的關(guān)于內(nèi)存屏障的講解基本不會(huì)超過這三篇文章,包括相關(guān)書籍中的介紹。問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實(shí)現(xiàn)原理? (4)volatile的缺陷? 簡(jiǎn)介 volatile...
摘要:前半句是指線程內(nèi)表現(xiàn)為串行的語(yǔ)義,后半句是指指令重排序現(xiàn)象和工作內(nèi)存和主內(nèi)存同步延遲現(xiàn)象。關(guān)于內(nèi)存模型的講解請(qǐng)參考死磕同步系列之。目前國(guó)內(nèi)市面上的關(guān)于內(nèi)存屏障的講解基本不會(huì)超過這三篇文章,包括相關(guān)書籍中的介紹。問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實(shí)現(xiàn)原理? (4)volatile的缺陷? 簡(jiǎn)介 volatile...
摘要:最近在看多線程相關(guān),看到這篇來自大神關(guān)于關(guān)鍵字的講解感覺非常詳細(xì)易懂,特此轉(zhuǎn)載一下。如果對(duì)增加聲明則所有線程對(duì)的寫都會(huì)立即刷新到主存中,而且所有對(duì)的讀也都直接從主存中去讀。 最近在看java多線程相關(guān),看到這篇來自大神Jakob Jenkov關(guān)于Volatile關(guān)鍵字的講解感覺非常詳細(xì)易懂,特此轉(zhuǎn)載一下。原文鏈接:http://tutorials.jenkov.com/j... 內(nèi)存可...
摘要:數(shù)據(jù)結(jié)構(gòu)重要成員變量代表整個(gè)哈希表??破眨鉀Q多線程并行情況下使用鎖造成性能損耗的一種機(jī)制,操作包含三個(gè)操作數(shù)內(nèi)存位置預(yù)期原值和新值。 ConcurrenHashMap 。下面分享一下我對(duì)ConcurrentHashMap 的理解,主要用于個(gè)人備忘。如果有不對(duì),請(qǐng)批評(píng)。 HashMap嚴(yán)重的勾起了我對(duì)HashMap家族的好奇心,下面分享一下我對(duì)ConcurrentHashMap 的理解...
閱讀 1859·2021-11-22 15:24
閱讀 1315·2021-11-12 10:36
閱讀 3216·2021-09-28 09:36
閱讀 1844·2021-09-02 15:15
閱讀 2759·2019-08-30 15:54
閱讀 2399·2019-08-30 11:02
閱讀 2398·2019-08-29 13:52
閱讀 3548·2019-08-26 11:53