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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

内存可见性和原子性:Synchronized和Volatile的比较

發(fā)布時(shí)間:2024/4/15 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存可见性和原子性:Synchronized和Volatile的比较 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Java多線程之內(nèi)存可見性和原子性:Synchronized和Volatile的比較

? ? 【尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處】http://blog.csdn.net/guyuealian/article/details/52525724 ? ? ?在說明Java多線程內(nèi)存可見性之前,先來簡(jiǎn)單了解一下Java內(nèi)存模型。 ? ? ?(1)Java所有變量都存儲(chǔ)在主內(nèi)存中
? ? ?(2)每個(gè)線程都有自己獨(dú)立的工作內(nèi)存,里面保存該線程的使用到的變量副本(該副本就是主內(nèi)存中該變量的一份拷貝)

? ?(1)線程對(duì)共享變量的所有操作都必須在自己的工作內(nèi)存中進(jìn)行,不能直接在主內(nèi)存中讀寫
? ?(2)不同線程之間無法直接訪問其他線程工作內(nèi)存中的變量,線程間變量值的傳遞需要通過主內(nèi)存來完成。
線程1對(duì)共享變量的修改,要想被線程2及時(shí)看到,必須經(jīng)過如下2個(gè)過程:
? ?(1)把工作內(nèi)存1中更新過的共享變量刷新到主內(nèi)存中
? ?(2)將主內(nèi)存中最新的共享變量的值更新到工作內(nèi)存2中

可見性與原子性
? ?可見性:一個(gè)線程對(duì)共享變量的修改,更夠及時(shí)的被其他線程看到
? ?原子性:即不可再分了,不能分為多步操作。比如賦值或者return。比如"a = 1;"和 "return a;"這樣的操作都具有原子性。類似"a += b"這樣的操作不具有原子性,在某些JVM中"a += b"可能要經(jīng)過這樣三個(gè)步驟:
① 取出a和b
② 計(jì)算a+b
③ 將計(jì)算結(jié)果寫入內(nèi)存

(1)Synchronized:保證可見性和原子性
? ? Synchronized能夠?qū)崿F(xiàn)原子性和可見性;在Java內(nèi)存模型中,synchronized規(guī)定,線程在加鎖時(shí),先清空工作內(nèi)存→在主內(nèi)存中拷貝最新變量的副本到工作內(nèi)存→執(zhí)行完代碼→將更改后的共享變量的值刷新到主內(nèi)存中→釋放互斥鎖

(2)Volatile:保證可見性,但不保證操作的原子性
? ? Volatile實(shí)現(xiàn)內(nèi)存可見性是通過store和load指令完成的;也就是對(duì)volatile變量執(zhí)行寫操作時(shí),會(huì)在寫操作后加入一條store指令,即強(qiáng)迫線程將最新的值刷新到主內(nèi)存中;而在讀操作時(shí),會(huì)加入一條load指令,即強(qiáng)迫從主內(nèi)存中讀入變量的值。但volatile不保證volatile變量的原子性,例如:
Private int Num=0;Num++;//Num不是原子操作? ? Num不是原子操作,因?yàn)槠淇梢苑譃?#xff1a;讀取Num的值,將Num的值+1,寫入最新的Num的值。
? ? 對(duì)于Num++;操作,線程1和線程2都執(zhí)行一次,最后輸出Num的值可能是:1或者2
? ?【解釋輸出結(jié)果1的解釋:當(dāng)線程1執(zhí)行Num++;語(yǔ)句時(shí),先是讀入Num的值為0,倘若此時(shí)讓出CPU執(zhí)行權(quán),線程獲得執(zhí)行,線程2會(huì)重新從主內(nèi)存中,讀入Num的值還是0,然后線程2執(zhí)行+1操作,最后把Num=1刷新到主內(nèi)存中;?線程2執(zhí)行完后,線程1由開始執(zhí)行,但之前已經(jīng)讀取的Num的值0,所以它還是在0的基礎(chǔ)上執(zhí)行+1操作,也就是還是等于1,并刷新到主內(nèi)存中。所以最終的結(jié)果是1 ? ? 一般在多線程中使用volatile變量,為了安全,對(duì)變量的寫入操作不能依賴當(dāng)前變量的值:如Num++或者Num=Num*5這些操作。
(3)Synchronized和Volatile的比較
? ? 1)Synchronized保證內(nèi)存可見性和操作的原子性
? ? 2)Volatile只能保證內(nèi)存可見性
? ? 3)Volatile不需要加鎖,比Synchronized更輕量級(jí),并不會(huì)阻塞線程(volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞。)
? ? 4)volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化,而synchronized標(biāo)記的變量可以被編譯器優(yōu)化(如編譯器重排序的優(yōu)化).
? ? 5)volatile是變量修飾符,僅能用于變量,而synchronized是一個(gè)方法或塊的修飾符。
? ? ? volatile本質(zhì)是在告訴JVM當(dāng)前變量在寄存器中的值是不確定的,使用前,需要先從主存中讀取,因此可以實(shí)現(xiàn)可見性。而對(duì)n=n+1,n++等操作時(shí),volatile關(guān)鍵字將失效,不能起到像synchronized一樣的線程同步(原子性)的效果。

【參考資料】《細(xì)說Java多線程之內(nèi)存可見性》http://www.imooc.com/video/6775(含視頻和代碼) 【相關(guān)習(xí)題】 (1)下列說法不正確的是()
A.當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí),一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行。
B.當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
C.當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),其他線程對(duì)object中所有其它synchronized(this)同步代碼塊的訪問不會(huì)被阻塞。
D.當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),它就獲得了這個(gè)object的對(duì)象鎖。結(jié)果,其它線程對(duì)該object對(duì)象所有同步代碼部分的訪問都被暫時(shí)阻塞。
答案:C,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),其他線程對(duì)object中所有其它synchronized(this)同步代碼塊的訪問將會(huì)被阻塞。
(2)下面敘述錯(cuò)誤的是:
A.通過synchronized和volatile都可以實(shí)現(xiàn)可見性
B.不同線程之間可以直接訪問其他線程工作內(nèi)存中的變量
C.線程對(duì)共享變量的所有操作都必須在自己的工作內(nèi)存中進(jìn)行
D.所有的變量都存儲(chǔ)在主內(nèi)存中
答案:B,不同線程之間無法直接訪問其他線程工作內(nèi)存中的變量

總結(jié)

以上是生活随笔為你收集整理的内存可见性和原子性:Synchronized和Volatile的比较的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。