成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

CAS

meislzhua / 3171人閱讀

摘要:如果程序是在多處理器上運(yùn)行,就為指令加上前綴。關(guān)于的鎖有如下種處理器自動(dòng)保證基本內(nèi)存操作的原子性首先處理器會(huì)自動(dòng)保證基本的內(nèi)存操作的原子性。使用緩存鎖保證原子性第二個(gè)機(jī)制是通過緩存鎖定保證原子性。

前言 概述

與鎖不同的是, CAS 是一種無鎖操作,一種無阻塞的算法,它實(shí)質(zhì)上不能說是一種鎖,而是將 CPU 充分利用起來的一種算法

CAS 廣泛應(yīng)用在數(shù)據(jù)結(jié)構(gòu)中,JDK中的 java.util.concurrent 并發(fā)包就是在其操作下建立的

眾所周知,JAVA 作為一門高級(jí)語言,是不支持一些底層處理的,例如指針,內(nèi)存控制等等,但大家可以看看 sun.misc.Unsafe 類,也是在它的支持下,JAVA 具備了對(duì)硬件級(jí)別原子操作的支持,這個(gè)包有很多應(yīng)用,例如 java.util.concurrent.atomic 包下的原子類都是基于其實(shí)現(xiàn) CAS 操作的

我的測(cè)試下,當(dāng)線程數(shù)量不大時(shí),CAS 要快于鎖,但線程數(shù)量很多很多時(shí),CAS 卻更慢了

參考

http://blog.csdn.net/hsuxu/ar...
http://www.cnblogs.com/mickol...

CAS 概述

舉個(gè)例子,如 i++,它是分三步的

先取內(nèi)存中的 i

再將 i 加上 1

最后將加完后的值賦給內(nèi)存中的 i

但若在其賦值前,i 的內(nèi)存值已經(jīng)被其他線程修改,此處肯定會(huì)丟失數(shù)據(jù),也就是說它是線程不安全的

如果給這個(gè)操作加上鎖,那代價(jià)未免也太大了,CAS 便可以更快地解決這個(gè)問題

原理

CAS 的原理其實(shí)很簡(jiǎn)單,主要分三個(gè)參數(shù)

內(nèi)存值 - 內(nèi)存里的實(shí)際值

舊期望值 - 操作前的值

新值 - 操作后的值

CAS 的操作簡(jiǎn)而言之就是 compare and swap

將內(nèi)存值與舊期望值比較

若相等,則說明此值在操作中沒有被其他線程改變過,并將新值賦給內(nèi)存值

若不等,則說明此值在操作中已經(jīng)被其他線程改變過,并一直自旋直到相等

ABA 問題

簡(jiǎn)而言之,ABA 問題就是,比如我取內(nèi)存值 A,在我比較之前,它被其他人改成了 B,然后又被其他人改回了 A,而我之后再做比較,相等成立,但是又會(huì)造成數(shù)據(jù)丟失的問題

CAS 真正比較的應(yīng)該是 值的狀態(tài),而不是值的大小,我可以給值附帶一個(gè) 版本號(hào),然后更新時(shí)對(duì)版本號(hào)進(jìn)行值大小的 CAS 操作,或者附帶一個(gè) 時(shí)間戳也是一樣的,像現(xiàn)在數(shù)據(jù)庫大部分都是采用附加版本號(hào)的方法

大家也可以看看 java.util.concurrent.atomic.AtomicStampedReference 是怎么解決 ABA 問題的,在這里就不講述了

缺點(diǎn)

如果每個(gè)人都在自旋,CPU 的開銷將是巨大的,關(guān)于本人的測(cè)試,當(dāng)線程數(shù)量很多很多時(shí),CAS 會(huì)更慢就是這個(gè)原因

AtomicInteger

我們來看看 java.util.concurrent.atomic.AtomicInteger 是怎么實(shí)現(xiàn)原子操作的,其主要成員如下

// Unsafe 類實(shí)例,具體的在下一篇文章詳細(xì)講,這里先跳過
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 值偏移量
private static final long valueOffset;
// 內(nèi)部封裝值
private volatile int value;
// unsafe 初始化
static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { 
        throw new Error(ex); 
    }
}

我們常用的 incrementAndGet 方法如下,在這里是直接調(diào)用 Unsafe 的 native 方法,實(shí)現(xiàn)硬件級(jí)別的原子操作,底層是用匯編實(shí)現(xiàn)的

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

這個(gè)本地方法在openjdk中依次調(diào)用的c++代碼為:unsafe.cpp,atomic.cpp和atomicwindowsx86.inline.hpp。這個(gè)本地方法的最終實(shí)現(xiàn)在openjdk的如下位置:openjdk-7-fcs-src-b147-27jun2011openjdkhotspotsrcoscpuwindowsx86vm atomicwindowsx86.inline.hpp(對(duì)應(yīng)于windows操作系統(tǒng),X86處理器)。下面是對(duì)應(yīng)于intel x86處理器的源代碼的片段:

// Adding a lock prefix to an instruction on MP machine
// VC++ doesn"t like the lock prefix to be on a single line
// so we can"t insert a label after the lock prefix.
// By emitting a lock prefix, we can define a label after it.
#define LOCK_IF_MP(mp) __asm cmp mp, 0  
                       __asm je L0      
                       __asm _emit 0xF0 
                       __asm L0:

inline jint Atomic::cmpxchg (jint exchange_value, 
                             volatile jint* dest, 
                             jint compare_value) {
  // alternative for InterlockedCompareExchange
  int mp = os::is_MP();
  __asm {
    mov edx, dest
    mov ecx, exchange_value
    mov eax, compare_value
    LOCK_IF_MP(mp)
    cmpxchg dword ptr [edx], ecx
  }
}

如上面源代碼所示,程序會(huì)根據(jù)當(dāng)前處理器的類型來決定是否為cmpxchg指令添加lock前綴。如果程序是在多處理器上運(yùn)行,就為cmpxchg指令加上lock前綴(lock cmpxchg)。反之,如果程序是在單處理器上運(yùn)行,就省略lock前綴(單處理器自身會(huì)維護(hù)單處理器內(nèi)的順序一致性,不需要lock前綴提供的內(nèi)存屏障效果)。

CPU

關(guān)于CPU的鎖有如下3種:

處理器自動(dòng)保證基本內(nèi)存操作的原子性

首先處理器會(huì)自動(dòng)保證基本的內(nèi)存操作的原子性。處理器保證從系統(tǒng)內(nèi)存當(dāng)中讀取或者寫入一個(gè)字節(jié)是原子的,意思是當(dāng)一個(gè)處理器讀取一個(gè)字節(jié)時(shí),其他處理器不能訪問這個(gè)字節(jié)的內(nèi)存地址。奔騰6和最新的處理器能自動(dòng)保證單處理器對(duì)同一個(gè)緩存行里進(jìn)行16/32/64位的操作是原子的,但是復(fù)雜的內(nèi)存操作處理器不能自動(dòng)保證其原子性,比如跨總線寬度,跨多個(gè)緩存行,跨頁表的訪問。但是處理器提供總線鎖定和緩存鎖定兩個(gè)機(jī)制來保證復(fù)雜內(nèi)存操作的原子性

使用總線鎖保證原子性

第一個(gè)機(jī)制是通過總線鎖保證原子性。如果多個(gè)處理器同時(shí)對(duì)共享變量進(jìn)行讀改寫(i++就是經(jīng)典的讀改寫操作)操作,那么共享變量就會(huì)被多個(gè)處理器同時(shí)進(jìn)行操作,這樣讀改寫操作就不是原子的,操作完之后共享變量的值會(huì)和期望的不一致,舉個(gè)例子:如果i=1,我們進(jìn)行兩次i++操作,我們期望的結(jié)果是3,但是有可能結(jié)果是2,如圖

原因是有可能多個(gè)處理器同時(shí)從各自的緩存中讀取變量i,分別進(jìn)行加一操作,然后分別寫入系統(tǒng)內(nèi)存當(dāng)中。那么想要保證讀改寫共享變量的操作是原子的,就必須保證CPU1讀改寫共享變量的時(shí)候,CPU2不能操作緩存了該共享變量內(nèi)存地址的緩存。

處理器使用總線鎖就是來解決這個(gè)問題的。所謂總線鎖就是使用處理器提供的一個(gè)LOCK#信號(hào),當(dāng)一個(gè)處理器在總線上輸出此信號(hào)時(shí),其他處理器的請(qǐng)求將被阻塞住,那么該處理器可以獨(dú)占使用共享內(nèi)存。

使用緩存鎖保證原子性

第二個(gè)機(jī)制是通過緩存鎖定保證原子性。在同一時(shí)刻我們只需保證對(duì)某個(gè)內(nèi)存地址的操作是原子性即可,但總線鎖定把CPU和內(nèi)存之間通信鎖住了,這使得鎖定期間,其他處理器不能操作其他內(nèi)存地址的數(shù)據(jù),所以總線鎖定的開銷比較大,最近的處理器在某些場(chǎng)合下使用緩存鎖定代替總線鎖定來進(jìn)行優(yōu)化。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67245.html

相關(guān)文章

  • CAS 5.2.x 單點(diǎn)登錄 - 搭建服務(wù)端和客戶端

    摘要:一簡(jiǎn)介單點(diǎn)登錄,簡(jiǎn)稱為,是目前比較流行的企業(yè)業(yè)務(wù)整合的解決方案之一??蛻舳藬r截未認(rèn)證的用戶請(qǐng)求,并重定向至服務(wù)端,由服務(wù)端對(duì)用戶身份進(jìn)行統(tǒng)一認(rèn)證。三搭建客戶端在官方文檔中提供了客戶端樣例,即。 一、簡(jiǎn)介 單點(diǎn)登錄(Single Sign On),簡(jiǎn)稱為 SSO,是目前比較流行的企業(yè)業(yè)務(wù)整合的解決方案之一。SSO的定義是在多個(gè)應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問所有相互信任的應(yīng)用系...

    Lin_YT 評(píng)論0 收藏0
  • 統(tǒng)一認(rèn)證 - Apereo CAS 客戶端的集成以及小結(jié)

    摘要:所以客戶端的集成主要是單點(diǎn)登錄的集成,客戶端指定需要做安全認(rèn)證的頁面,然后的安全包檢測(cè)校驗(yàn)用戶登錄情況,并自動(dòng)與登錄頁面進(jìn)行跳轉(zhuǎn)交互。提供了很多配置的方式,有,,以及其他可查官網(wǎng)。但高度自由的一如既往的,沒有提供可視化操作的界面。 前兩篇介紹了Apereo CAS以及服務(wù)器端的安裝,但還不夠完整,服務(wù)端還沒有Application真正用起來呢!這篇文章將介紹怎么用起來 集成的目的 客戶...

    AbnerMing 評(píng)論0 收藏0
  • spring系列---CAS客戶端與SpringSecurity集成

    摘要:客戶端與集成指定端口請(qǐng)求路徑用于單點(diǎn)退出,該過濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置該過濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置。該過濾器使得開發(fā)者可以通過來獲取用戶的登錄名。 CAS客戶端與SpringSecurity集成 pom.xml org.springframework spring-context 4.3.9....

    hizengzeng 評(píng)論0 收藏0
  • 從http驗(yàn)證流程解析CAS單點(diǎn)登錄

    JAVA單點(diǎn)登錄有好多種方式,譬如用cookie的domain做,用中間代理做等等,但都需要自行做許多開發(fā)工作。而其中耶魯大學(xué)的開源項(xiàng)目CAS提供了一個(gè)一站式解決方案,只需很少的擴(kuò)展即可輕松實(shí)現(xiàn)企業(yè)級(jí)單點(diǎn)登錄?;A(chǔ)知識(shí)網(wǎng)上其他挺多的,這里我就不詳述了。本文通過分析http請(qǐng)求過程中httpheader,cookie等數(shù)據(jù)剖析了cas(非代理模式,默認(rèn)驗(yàn)證邏輯。其他如restletAPI等可擴(kuò)展邏輯...

    honhon 評(píng)論0 收藏0
  • 前后端分離下的CAS跨域流程分析

    摘要:這種情況通常發(fā)生在反向代理的時(shí)候,前端發(fā)起請(qǐng)求代理服務(wù)器,代理服務(wù)器發(fā)起請(qǐng)求到,這時(shí)候就容易導(dǎo)致域名不一致,請(qǐng)一定要注意這點(diǎn)。 寫在最前 前后端分離其實(shí)有兩類: 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件整個(gè)放入后端項(xiàng)目中。 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件放入單獨(dú)的靜態(tài)資源服務(wù)器中,如nginx。 這兩種方案最大的區(qū)別就是生產(chǎn)階段。由于第...

    ckllj 評(píng)論0 收藏0
  • 前后端分離下的CAS跨域流程分析

    摘要:這種情況通常發(fā)生在反向代理的時(shí)候,前端發(fā)起請(qǐng)求代理服務(wù)器,代理服務(wù)器發(fā)起請(qǐng)求到,這時(shí)候就容易導(dǎo)致域名不一致,請(qǐng)一定要注意這點(diǎn)。 寫在最前 前后端分離其實(shí)有兩類: 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件整個(gè)放入后端項(xiàng)目中。 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件放入單獨(dú)的靜態(tài)資源服務(wù)器中,如nginx。 這兩種方案最大的區(qū)別就是生產(chǎn)階段。由于第...

    DevTalking 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<