日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java中 volatile 关键字的最全总结,快给自己查缺补漏吧!

發布時間:2025/3/21 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中 volatile 关键字的最全总结,快给自己查缺补漏吧! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:老鼠只愛大米

來源:blog.csdn.net/u012723673/article/details/80682208

一、簡介

volatile是Java提供的一種輕量級的同步機制。Java 語言包含兩種內在的同步機制:同步塊(或方法)和 volatile 變量,相比于synchronized(synchronized通常稱為重量級鎖),volatile更輕量級,因為它不會引起線程上下文的切換和調度。但是volatile 變量的同步性較差(有時它更簡單并且開銷更低),而且其使用也更容易出錯。

二、并發編程的3個基本概念

(1)原子性

定義:即一個操作或者多個操作 要么全部執行并且執行的過程不會被任何因素打斷,要么就都不執行。

原子性是拒絕多線程操作的,不論是多核還是單核,具有原子性的量,同一時刻只能有一個線程來對它進行操作。簡而言之,在整個操作過程中不會被線程調度器中斷的操作,都可認為是原子性。例如 a=1是原子性操作,但是a++和a +=1就不是原子性操作。

Java中的原子性操作包括:

a. 基本類型的讀取和賦值操作,且賦值必須是數字賦值給變量,變量之間的相互賦值不是原子性操作。

b.所有引用reference的賦值操作

c.java.concurrent.Atomic.* 包中所有類的一切操作

(2)可見性

定義:指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。

在多線程環境下,一個線程對共享變量的操作對其他線程是不可見的。Java提供了volatile來保證可見性,當一個變量被volatile修飾后,表示著線程本地內存無效,當一個線程修改共享變量后他會立即被更新到主內存中,其他線程讀取共享變量時,會直接從主內存中讀取。

當然,synchronize和Lock都可以保證可見性。synchronized和Lock能保證同一時刻只有一個線程獲取鎖然后執行同步代碼,并且在釋放鎖之前會將對變量的修改刷新到主存當中。因此可以保證可見性。

(3)有序性

定義:即程序執行的順序按照代碼的先后順序執行。

Java內存模型中的有序性可以總結為:如果在本線程內觀察,所有操作都是有序的;如果在一個線程中觀察另一個線程,所有操作都是無序的。前半句是指“線程內表現為串行語義”,后半句是指“指令重排序”現象和“工作內存主主內存同步延遲”現象。

在Java內存模型中,為了效率是允許編譯器和處理器對指令進行重排序,當然重排序不會影響單線程的運行結果,但是對多線程會有影響。Java提供volatile來保證一定的有序性。最著名的例子就是單例模式里面的DCL(雙重檢查鎖)。

另外,可以通過synchronized和Lock來保證有序性,synchronized和Lock保證每個時刻是有一個線程執行同步代碼,相當于是讓線程順序執行同步代碼,自然就保證了有序性。

三、鎖的互斥和可見性

鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性(visibility)。

(1)互斥即一次只允許一個線程持有某個特定的鎖,一次就只有一個線程能夠使用該共享數據。

(2)可見性要更加復雜一些,它必須確保釋放鎖之前對共享數據做出的更改對于隨后獲得該鎖的另一個線程是可見的。也即當一條線程修改了共享變量的值,新值對于其他線程來說是可以立即得知的。如果沒有同步機制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發許多嚴重問題。

要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:

a.對變量的寫操作不依賴于當前值。

b.該變量沒有包含在具有其他變量的不變式中。

實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立于任何程序的狀態,包括變量的當前狀態。事實上就是保證操作是原子性操作,才能保證使用volatile關鍵字的程序在并發時能夠正確執行。

四、Java的內存模型JMM以及共享變量的可見性

JMM決定一個線程對共享變量的寫入何時對另一個線程可見,JMM定義了線程和主內存之間的抽象關系:共享變量存儲在主內存(Main Memory)中,每個線程都有一個私有的本地內存(Local Memory),本地內存保存了被該線程使用到的主內存的副本拷貝,線程對變量的所有操作都必須在工作內存中進行,而不能直接讀寫主內存中的變量。

對于普通的共享變量來講,線程A將其修改為某個值發生在線程A的本地內存中,此時還未同步到主內存中去;而線程B已經緩存了該變量的舊值,所以就導致了共享變量值的不一致。解決這種共享變量在多線程模型中的不可見性問題,較粗暴的方式自然就是加鎖,但是此處使用synchronized或者Lock這些方式太重量級了,比較合理的方式其實就是volatile。

需要注意的是,JMM是個抽象的內存模型,所以所謂的本地內存,主內存都是抽象概念,并不一定就真實的對應cpu緩存和物理內存

五、volatile變量的特性

(1)保證可見性,不保證原子性

a.當寫一個volatile變量時,JMM會把該線程本地內存中的變量強制刷新到主內存中去;

b.這個寫會操作會導致其他線程中的緩存無效。

(2)禁止指令重排

重排序是指編譯器和處理器為了優化程序性能而對指令序列進行排序的一種手段。重排序需要遵守一定規則:

a.重排序操作不會對存在數據依賴關系的操作進行重排序。

比如:a=1;b=a; 這個指令序列,由于第二個操作依賴于第一個操作,所以在編譯時和處理器運行時這兩個操作不會被重排序。

b.重排序是為了優化性能,但是不管怎么重排序,單線程下程序的執行結果不能被改變

比如:a=1;b=2;c=a+b這三個操作,第一步(a=1)和第二步(b=2)由于不存在數據依賴關系, 所以可能會發生重排序,但是c=a+b這個操作是不會被重排序的,因為需要保證最終的結果一定是c=a+b=3。

重排序在單線程下一定能保證結果的正確性,但是在多線程環境下,可能發生重排序,影響結果,下例中的1和2由于不存在數據依賴關系,則有可能會被重排序,先執行status=true再執行a=2。而此時線程B會順利到達4處,而線程A中a=2這個操作還未被執行,所以b=a+1的結果也有可能依然等于2。

使用volatile關鍵字修飾共享變量便可以禁止這種重排序。若用volatile修飾共享變量,在編譯時,會在指令序列中插入內存屏障來禁止特定類型的處理器重排序,volatile禁止指令重排序也有一些規則:

a.當程序執行到volatile變量的讀操作或者寫操作時,在其前面的操作的更改肯定全部已經進行,且結果已經對后面的操作可見;在其后面的操作肯定還沒有進行;

b.在進行指令優化時,不能將在對volatile變量訪問的語句放在其后面執行,也不能把volatile變量后面的語句放到其前面執行。

即執行到volatile變量時,其前面的所有語句都執行完,后面所有語句都未執行。且前面語句的結果對volatile變量及其后面語句可見。

六、volatile不適用的場景

(1)volatile不適合復合操作

例如,inc++不是一個原子性操作,可以由讀取、加、賦值3步組成,所以結果并不能達到30000。.

(2)解決方法

1.采用synchronized

2.采用Lock

3.采用java并發包中的原子操作類,原子操作類是通過CAS循環的方式來保證其原子性的

七、volatile原理

volatile可以保證線程可見性且提供了一定的有序性,但是無法保證原子性。在JVM底層volatile是采用“內存屏障”來實現的。觀察加入volatile關鍵字和沒有加入volatile關鍵字時所生成的匯編代碼發現,加入volatile關鍵字時,會多出一個lock前綴指令,lock前綴指令實際上相當于一個內存屏障(也成內存柵欄),內存屏障會提供3個功能:

I. 它確保指令重排序時不會把其后面的指令排到內存屏障之前的位置,也不會把前面的指令排到內存屏障的后面;即在執行到內存屏障這句指令時,在它前面的操作已經全部完成;

II. 它會強制將對緩存的修改操作立即寫入主存;

III. 如果是寫操作,它會導致其他CPU中對應的緩存行無效。

八、單例模式的雙重鎖為什么要加volatile

需要volatile關鍵字的原因是,在并發情況下,如果沒有volatile關鍵字,在第5行會出現問題。instance = new TestInstance();可以分解為3行偽代碼

a. memory = allocate() //分配內存

b. ctorInstanc(memory) //初始化對象

c. instance = memory //設置instance指向剛分配的地址

上面的代碼在編譯運行時,可能會出現重排序從a-b-c排序為a-c-b。在多線程的情況下會出現以下問題。當線程A在執行第5行代碼時,B線程進來執行到第2行代碼。假設此時A執行的過程中發生了指令重排序,即先執行了a和c,沒有執行b。那么由于A線程執行了c導致instance指向了一段地址,所以B線程判斷instance不為null,會直接跳到第6行并返回一個未初始化的對象。

總結

以上是生活随笔為你收集整理的Java中 volatile 关键字的最全总结,快给自己查缺补漏吧!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 爱情岛av永久入口 | 高清无打码 | 国产黄色精品视频 | 精品国产一区二区三区四 | 狠狠v欧美v日韩v亚洲ⅴ | 麻豆chinese新婚xxx | 亚洲一二三区在线观看 | 国产又粗又黄又猛 | 久久久久女 | 97超级碰碰人妻中文字幕 | 天堂一级片 | 久久久香蕉视频 | 一级特级毛片 | 欧美xxxx性xxxxx高清 | 亚欧美在线观看 | 久久h视频 | 东京热一区二区三区四区 | 久久国产激情视频 | 色呦呦视频在线观看 | 国产精品va无码一区二区 | 成人毛片18女人毛片免费 | 欧美日韩一区二区三区在线 | 欧美激情天堂 | 中日韩av在线 | 国产普通话bbwbbwbbw | 欧美成人三级在线 | 成人在线观看一区二区三区 | 女人张开双腿让男人捅 | 日韩激情在线观看 | 久久性生活 | 福利在线观看 | 日本视频在线观看 | 国内精品久久久久久久久久 | 97久久国产亚洲精品超碰热 | 免费看污黄网站在线观看 | 国产91精品一区二区绿帽 | 97se视频 | 99热最新| 女人裸体免费网站 | 亚洲大尺度网站 | 亚洲国产精品久久久久爰性色 | 黄色免费一级片 | 亚洲图片视频小说 | 午夜精品视频在线观看 | 欧美精品系列 | 久青草影视 | 黄色xxxxx | 欧美极品一区二区三区 | 在线观看免费观看 | 大胸美女吻戏 | 天天摸日日摸狠狠添 | 午夜嘿嘿 | 奇米网久久| 777米奇影视第四色 五月丁香久久婷婷 | a级片网址 | 国产主播专区 | 中国一级片黄色一级片黄 | 羞羞答答av | 九九在线观看高清免费 | 日韩深夜在线 | 亚洲综合情 | 日韩av男人的天堂 | 无码国产色欲xxxx视频 | 三a大片 | 亚洲精品动漫在线观看 | 亚洲国产aⅴ精品一区二区 日韩黄色在线视频 | 国产综合视频 | 亚洲视频免费在线观看 | 欧美又大粗又爽又黄大片视频 | 巨乳女教师的诱惑 | 美国免费高清电影在线观看 | 亚洲中文字幕无码爆乳av | 天天干天天日 | 变态另类ts人妖一区二区 | 亚洲一区二区电影网 | 玩偶姐姐在线看 | 欧美精品久久久久久久自慰 | 亚洲风情亚aⅴ在线发布 | 久久亚洲精品中文字幕 | 俄罗斯精品一区二区三区 | 亚洲成人午夜在线 | 国产福利在线视频观看 | 香蕉视频在线观看网站 | 不卡视频一区二区 | 一级作爱视频 | 欧美亚洲一区二区三区四区 | 国产精品久久久久久久久久久久久久久 | 国产又粗又猛视频免费 | 亲切的金子餐桌片段的金子 | 亚洲无在线观看 | av不卡在线看 | 青青草超碰 | 日日夜夜综合网 | 成年人的免费视频 | 欧美极品videos精品 | 体内精69xxxxxx | 国产精品无码av在线播放 | 中国女人黄色大片 | 欧美精品在线视频 |