最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

學(xué)習(xí)非阻塞的同步機(jī)制CAS

 更新時間:2019年05月31日 16:01:41   作者:展翅而飛  
現(xiàn)代的處理器都包含對并發(fā)的支持,其中最通用的方法就是比較并交換(compare and swap),簡稱CAS。下面我們來一起學(xué)習(xí)一下吧

在研究線程池的執(zhí)行原理時,看到一段不斷循環(huán)重試的代碼,不理解它的原理,看注釋這是CAS的實現(xiàn),所以學(xué)會之后記錄下來。

鎖有什么劣勢

在多線程并發(fā)下,可以通過加鎖來保證線程安全性,但多個線程同時請求鎖,很多情況下避免不了要借助操作系統(tǒng),線程掛起和恢復(fù)會存在很大的開銷,并存在很長時間的中斷。一些細(xì)粒度的操作,例如同步容器,操作往往只有很少代碼量,如果存在鎖并且線程激烈地競爭,調(diào)度的代價很大。
總結(jié)來說,線程持有鎖,會讓其他需要鎖的線程阻塞,產(chǎn)生多種風(fēng)險和開銷。加鎖是一種悲觀方法,線程總是設(shè)想在自己持有資源的同時,肯定有其他線程想要資源,不牢牢鎖住資源還不能放心呢。
在硬件的支持下,出現(xiàn)了非阻塞的同步機(jī)制,其中一種常用實現(xiàn)就是CAS。

什么是CAS

現(xiàn)代的處理器都包含對并發(fā)的支持,其中最通用的方法就是比較并交換(compare and swap),簡稱CAS。

CAS 操作包含三個操作數(shù) —— 內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。如果內(nèi)存位置的值與預(yù)期原值相匹配,那么處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論V值是否等于A值,都將返回V的原值。CAS 有效地說明了:我認(rèn)為位置 V 應(yīng)該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現(xiàn)在的值即可。

當(dāng)多個線程嘗試使用CAS同時更新一個變量,最終只有一個線程會成功,其他線程都會失敗。但和使用鎖不同,失敗的線程不會被阻塞,而是被告之本次更新操作失敗了,可以再試一次。此時,線程可以根據(jù)實際情況,繼續(xù)重試或者跳過操作,大大減少因為阻塞而損失的性能。所以,CAS是一種樂觀的操作,它希望每次都能成功地執(zhí)行更新操作。

public class SimulationCAS {
private int value;
public synchronized int get() {
return value;
}
public synchronized boolean compareAndSet(int expectedValue, int newValue) {
if (expectedValue == compareAndSwap(expectedValue, newValue)) {
return true;
}
return false;
}
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (oldValue == expectedValue) {
value = newValue;
}
return oldValue;
}
}

上面的代碼模擬了CAS的操作,其中compareAndSwap是CAS語義的體現(xiàn),compareAndSet對value進(jìn)行了更新操作,并返回成功與否。
幾行代碼就實現(xiàn)了CAS,是不是覺得很簡單呢?但你要知道,CAS僅僅告訴你操作結(jié)果,操作失敗后一系列重試回退放棄等操作都要自己實現(xiàn),開發(fā)起來遠(yuǎn)比使用鎖復(fù)雜。

Atom原子類

JVM是支持CAS的,體現(xiàn)在我們常用的Atom原子類,拿AtomicInteger分析一下源碼。

public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}

對AtomicInteger進(jìn)行+1操作,循環(huán)里,會將當(dāng)前值和+1后的目標(biāo)值傳入compareAndSet,直到成功才跳出方法。compareAndSet是不是很熟悉呢,接著來看看它的代碼。

// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

compareAndSet調(diào)用了unsafe.compareAndSwapInt,這是一個native方法,原理就是調(diào)用硬件支持的CAS方法??炊@個應(yīng)該就能明白Atom類的原理,其他方法的實現(xiàn)是類似的。

線程池里的CAS

有了CAS的基礎(chǔ)后,可以來研究那段我未看懂的代碼。
提交一個執(zhí)行任務(wù),線程池會嘗試增加一個工作線程去處理任務(wù)。下面是ThreadPoolExecutor里addWorker的一段代碼:

private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}

//其他省略

在內(nèi)循環(huán)里,會調(diào)用compareAndIncrementWorkerCount方法增加一個工作線程,原理和AtomicInteger的getAndIncrement方法是一樣的。如果增加成功,直接跳出循環(huán),否則在檢查線程池狀態(tài)后,再次在內(nèi)循環(huán)調(diào)用compareAndIncrementWorkerCount,直到添加成功。

現(xiàn)在再看代碼,瞬間就明白了。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于RocketMQ推拉模式詳解

    基于RocketMQ推拉模式詳解

    這篇文章主要介紹了RocketMQ推拉模式的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java?SE判斷兩個文件內(nèi)容是否相同的多種方法代碼

    Java?SE判斷兩個文件內(nèi)容是否相同的多種方法代碼

    昨天因為要幫師兄的忙所以看了一下如何判斷兩個文件內(nèi)容是否相同,這里給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于Java?SE判斷兩個文件內(nèi)容是否相同的多種方法,需要的朋友可以參考下
    2023-11-11
  • Java如何調(diào)用Matlab程序

    Java如何調(diào)用Matlab程序

    這篇文章主要介紹了Java如何調(diào)用Matlab程序的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java?移動文件,并修改名稱方式

    java?移動文件,并修改名稱方式

    這篇文章主要介紹了java?移動文件,并修改名稱方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java 反射機(jī)制

    Java 反射機(jī)制

    這篇文章簡要的說明了Java的反射機(jī)制,Java的反射是框架設(shè)計的靈魂,本文通過例子能看的更加清晰的理解
    2021-06-06
  • SpringBoot使用JUL實現(xiàn)日志記錄功能

    SpringBoot使用JUL實現(xiàn)日志記錄功能

    在SpringBoot中,我們可以使用多種日志框架進(jìn)行日志記錄,其中,JUL(Java Util Logging)是Java平臺自帶的日志框架,它提供了簡單的 API 和配置,可以輕松地進(jìn)行日志記錄,本文將介紹如何在 SpringBoot中使用JUL進(jìn)行日志記錄,并提供示例代碼
    2023-06-06
  • java使用poi導(dǎo)出Excel的方法

    java使用poi導(dǎo)出Excel的方法

    這篇文章主要為大家詳細(xì)介紹了java使用poi導(dǎo)出Excel的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • springboot 集成pgsql+mybatis plus的詳細(xì)步驟

    springboot 集成pgsql+mybatis plus的詳細(xì)步驟

    集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步驟與 MyBatis 類似,只不過在 MyBatis Plus 中提供了更多的便利功能,如自動生成 SQL、分頁查詢、Wrapper 查詢等,下面分步驟給大家介紹springboot 集成pgsql+mybatis plus的過程,感興趣的朋友一起看看吧
    2023-12-12
  • Java數(shù)據(jù)結(jié)構(gòu)之隊列(動力節(jié)點Java學(xué)院整理)

    Java數(shù)據(jù)結(jié)構(gòu)之隊列(動力節(jié)點Java學(xué)院整理)

    隊列(Queue)是只允許在一端進(jìn)行插入,而在另一端進(jìn)行刪除的運算受限的線性表。 這篇文章詳細(xì)給大家介紹了java數(shù)據(jù)結(jié)構(gòu)之隊列,感興趣的朋友跟隨小編一起學(xué)習(xí)吧
    2017-04-04
  • 詳解springmvc攔截器攔截靜態(tài)資源

    詳解springmvc攔截器攔截靜態(tài)資源

    本篇文章主要介紹了詳解springmvc攔截器攔截靜態(tài)資源,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-01-01

最新評論

繁昌县| 三门峡市| 顺昌县| 吉木萨尔县| 潜江市| 麻江县| 昌黎县| 新平| 丰镇市| 屏边| 永定县| 交城县| 积石山| 鄂伦春自治旗| 连平县| 玉林市| 上虞市| 连山| 武义县| 秭归县| 岑巩县| 明水县| 蓝田县| 科技| 郴州市| 门头沟区| 正镶白旗| 赤水市| 元谋县| 昭苏县| 凤冈县| 盐亭县| 裕民县| 甘肃省| 景泰县| 桂东县| 漠河县| 米林县| 新兴县| 乌审旗| 南乐县|