欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

全面了解Java中的CAS機(jī)制

 更新時(shí)間:2017年10月09日 09:53:44   作者:HankingHu  
下面小編就為大家?guī)?lái)一篇全面了解Java中的CAS機(jī)制。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

前言

在看到Java鎖機(jī)制的時(shí)候,無(wú)意中看到了CAS這個(gè)詞,然后在百度查找CAS看了很多文章始終沒(méi)有看的太懂,今天又在Google上查找了一些資料,才算是真正弄清楚了CAS機(jī)制。

什么是CAS

在jdk 1.5中增加的一個(gè)最主要的支持是Atomic類,比如說(shuō)AtomicInteger, AtomicLong,這些類可幫助最大限度地減少在多線程中對(duì)于一些基本操作(例如,增加或減少多個(gè)線程之間共享的值)的復(fù)雜性。而這些類的實(shí)現(xiàn)都依賴于CAS(compare and swap)的算法。

樂(lè)觀鎖和悲觀鎖

cpu是時(shí)分復(fù)用的,也就是把cpu的時(shí)間片,分配給不同的thread/process輪流執(zhí)行,時(shí)間片與時(shí)間片之間,需要進(jìn)行cpu切換,也就是會(huì)發(fā)生進(jìn)程的切換。切換涉及到清空寄存器,緩存數(shù)據(jù)。然后重新加載新的thread所需數(shù)據(jù)。當(dāng)一個(gè)線程被掛起時(shí),加入到阻塞隊(duì)列,在一定的時(shí)間或條件下,在通過(guò)notify(),notifyAll()喚醒回來(lái)。在某個(gè)資源不可用的時(shí)候,就將cpu讓出,把當(dāng)前等待線程切換為阻塞狀態(tài)。等到資源(比如一個(gè)共享數(shù)據(jù))可用了,那么就將線程喚醒,讓他進(jìn)入runnable狀態(tài)等待cpu調(diào)度。這就是典型的悲觀鎖的實(shí)現(xiàn)。獨(dú)占鎖是一種悲觀鎖,synchronized就是一種獨(dú)占鎖,它假設(shè)最壞的情況,并且只有在確保其它線程不會(huì)造成干擾的情況下執(zhí)行,會(huì)導(dǎo)致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。

但是,由于在進(jìn)程掛起和恢復(fù)執(zhí)行過(guò)程中存在著很大的開(kāi)銷。當(dāng)一個(gè)線程正在等待鎖時(shí),它不能做任何事,所以悲觀鎖有很大的缺點(diǎn)。舉個(gè)例子,如果一個(gè)線程需要某個(gè)資源,但是這個(gè)資源的占用時(shí)間很短,當(dāng)線程第一次搶占這個(gè)資源時(shí),可能這個(gè)資源被占用,如果此時(shí)掛起這個(gè)線程,可能立刻就發(fā)現(xiàn)資源可用,然后又需要花費(fèi)很長(zhǎng)的時(shí)間重新?lián)屨兼i,時(shí)間代價(jià)就會(huì)非常的高。

樂(lè)觀鎖思路就是,每次不加鎖而是假設(shè)沒(méi)有沖突而去完成某項(xiàng)操作,如果因?yàn)闆_突失敗就重試,直到成功為止。某個(gè)線程可以不讓出cpu,而是一直while循環(huán),如果失敗就重試,直到成功為止。所以,當(dāng)數(shù)據(jù)爭(zhēng)用不嚴(yán)重時(shí),樂(lè)觀鎖效果更好。比如CAS就是一種樂(lè)觀鎖思想的應(yīng)用。

CAS(Compare and Swap )算法

CAS中有三個(gè)核心參數(shù):

1.主內(nèi)存中存放的V值,所有線程共享。

2.線程上次從內(nèi)存中讀取的V值A(chǔ)存放在線程的幀棧中,每個(gè)線程私有。

3.需要寫(xiě)入內(nèi)存中并改寫(xiě)V值的B值。也就是線程對(duì)A值操作后放入到主存V中。

上面說(shuō)的比較抽象,看下面的這幅圖比較容易理解。

如上圖中,主存中保存V值,線程中要使用V值要先從主存中讀取V值到線程的工作內(nèi)存A中,然后計(jì)算后變成B值,最后再把B值寫(xiě)回到內(nèi)存V值中。多個(gè)線程共用V值都是如此操作。CAS的核心是在將B值寫(xiě)入到V之前要比較A值和V值是否相同,如果不相同證明此時(shí)V值已經(jīng)被其他線程改變,重新將V值賦給A,并重新計(jì)算得到B,如果相同,則將B值賦給V。

如果不使用CAS機(jī)制,看看存在什么問(wèn)題,假如V=1,現(xiàn)在Thread1要對(duì)V進(jìn)行加1,Thread2也要對(duì)V進(jìn)行加1,首先Thread1讀取V=1到自己工作內(nèi)存A中此時(shí)A=1,假設(shè)Thread2此時(shí)也讀取V=1到自己的工作內(nèi)存A中,分別進(jìn)行加1操作后,兩個(gè)線程中B的值都為2,此時(shí)寫(xiě)回到V中時(shí)發(fā)現(xiàn)V的值為2,但是兩個(gè)線程分別對(duì)V進(jìn)行加處理結(jié)果卻只加了1有問(wèn)題。

CAS核心代碼

if (A==V)
{
  V = B
  return B;
}  
 else
  return V;

上面的操作是原子操作,現(xiàn)在來(lái)看看如果兩個(gè)線程同時(shí)要對(duì)V進(jìn)行加1操作使用上面的CAS機(jī)制后能不能獲得正確結(jié)果。

①Thread 1和Thread2 要對(duì)V進(jìn)行加1,Thread1和Thread2同時(shí)讀取v值并且對(duì)V執(zhí)行加1操作。

初始值 v=1,A=0, B=0。

②假設(shè)Thread1,Thread 2先讀取V值賦給A,并且對(duì)A進(jìn)行加1,得到B=2。

V=1,T1_A=1,T1_B=2;T2_A=1

Thread1要將T1_B寫(xiě)入V中,先要執(zhí)行CAS操作:

if (T1_A==V)
{
  V = T1_B
  return T1_B;
}  
 else
  return V;

因?yàn)門1_A=1=V,所以執(zhí)行 V=T1_B=2,此時(shí)V=2。

③Thread2也要對(duì)V執(zhí)行加操作。執(zhí)行加操作之后

V=2 ,T2_A=1,T2_B=2,

當(dāng)Thread2要將T2_B值寫(xiě)要V中之前要執(zhí)行CAS操作,

if (T2_A==V)
{
  V = T2_B
  return T2_B;
}  
 else
  return V;

此時(shí)T2_A=1,V=2, T2_A!=V,這時(shí)候返回V=2,給T2_A,T2_A=V=2,然后再次對(duì)T2_A進(jìn)行加1,得到T2_B,此時(shí)T2_B=3,T2_A=2,比較T2_A==V,所以將T2_B的值賦給T2_V,T2_V=T2_B=3。最后結(jié)果為3。正確。

CAS中的ABA問(wèn)題

如果一開(kāi)始位置V得到的舊值是A,當(dāng)進(jìn)行賦值操作時(shí)再次讀取發(fā)現(xiàn)仍然是A,并不能說(shuō)明變量沒(méi)有被其它線程改變過(guò)。有可能是其它線程將變量改為了B,后來(lái)又改回了A。大部分情況下ABA問(wèn)題不會(huì)影響程序并發(fā)的正確性,如果要解決ABA問(wèn)題,用傳統(tǒng)的互斥同步可能比原子類更高效。

ABA問(wèn)題的解決辦法

1.在變量前面追加版本號(hào):每次變量更新就把版本號(hào)加1,則A-B-A就變成1A-2B-3A。

2.atomic包下的AtomicStampedReference類:其compareAndSet方法首先檢查當(dāng)前引用是否等于預(yù)期引用,并且當(dāng)前標(biāo)志是否等于預(yù)期標(biāo)志,如果全部相等,則以原子方式將該引用的該標(biāo)志的值設(shè)置為給定的更新值。

以上這篇全面了解Java中的CAS機(jī)制就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中上傳圖片壓縮處理的方法示例

    Java中上傳圖片壓縮處理的方法示例

    本篇文章主要介紹了Java中圖片壓縮處理的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • Java Spring分別實(shí)現(xiàn)定時(shí)任務(wù)方法

    Java Spring分別實(shí)現(xiàn)定時(shí)任務(wù)方法

    這篇文章主要為大家詳細(xì)介紹了Java與Spring設(shè)置動(dòng)態(tài)定時(shí)任務(wù)的方法,定時(shí)任務(wù)的應(yīng)用場(chǎng)景十分廣泛,如定時(shí)清理文件、定時(shí)生成報(bào)表、定時(shí)數(shù)據(jù)同步備份等
    2022-07-07
  • 詳解MyBatis-Puls中saveBatch批量添加慢的問(wèn)題

    詳解MyBatis-Puls中saveBatch批量添加慢的問(wèn)題

    本文主要介紹了詳解MyBatis-Puls中saveBatch批量添加慢的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • 教你怎么用Java實(shí)現(xiàn)給圖片打上水印

    教你怎么用Java實(shí)現(xiàn)給圖片打上水印

    這篇文章主要介紹了教你怎么用Java實(shí)現(xiàn)給圖片打上水印,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • java如何獲取用戶登錄ip、瀏覽器信息、SessionId

    java如何獲取用戶登錄ip、瀏覽器信息、SessionId

    這篇文章主要介紹了java如何獲取用戶登錄ip、瀏覽器信息、SessionId,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java用jxl讀取excel并保存到數(shù)據(jù)庫(kù)的方法

    Java用jxl讀取excel并保存到數(shù)據(jù)庫(kù)的方法

    這篇文章主要為大家詳細(xì)介紹了Java用jxl讀取excel并保存到數(shù)據(jù)庫(kù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Struts2學(xué)習(xí)筆記(3)-DMI動(dòng)態(tài)調(diào)用方式

    Struts2學(xué)習(xí)筆記(3)-DMI動(dòng)態(tài)調(diào)用方式

    本文主要介紹Struts2的DMI動(dòng)態(tài)調(diào)用的兩種方式,簡(jiǎn)單實(shí)用,希望能給大家做一個(gè)參考。
    2016-06-06
  • SpringBoot中AOP的動(dòng)態(tài)匹配和靜態(tài)匹配詳解

    SpringBoot中AOP的動(dòng)態(tài)匹配和靜態(tài)匹配詳解

    這篇文章主要介紹了SpringBoot中AOP的動(dòng)態(tài)匹配和靜態(tài)匹配詳解,在創(chuàng)建代理的時(shí)候?qū)δ繕?biāo)類的每個(gè)連接點(diǎn)使用靜態(tài)切點(diǎn)檢查,如果僅通過(guò)靜態(tài)切點(diǎn)檢查就可以知道連接點(diǎn)是不匹配的,則在運(yùn)行時(shí)就不再進(jìn)行動(dòng)態(tài)檢查了,需要的朋友可以參考下
    2023-09-09
  • SpringBoot普通類獲取spring容器中bean的操作

    SpringBoot普通類獲取spring容器中bean的操作

    這篇文章主要介紹了SpringBoot普通類獲取spring容器中bean的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • SpringBoot3.x打包Docker容器的實(shí)現(xiàn)

    SpringBoot3.x打包Docker容器的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot3.x打包Docker容器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評(píng)論