久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

深入理解Java8并發(fā)工具類StampedLock

 jackeyqing 2018-08-17

StampedLock類是JDK8里面新增的一個(gè)并發(fā)工具類,,這個(gè)類比較特殊,在此之前我們先簡單的了解一下關(guān)于數(shù)據(jù)庫或者存儲(chǔ)系統(tǒng)的鎖策略和機(jī)制,。

總體上來說鎖有兩大類:

悲觀鎖:總是認(rèn)為會(huì)有沖突發(fā)生,,所以每次操作臨界區(qū)資源時(shí)都會(huì)加鎖。

樂觀鎖:顧名思義,認(rèn)為每次操作臨界區(qū)資源時(shí)不會(huì)發(fā)生沖突,,但會(huì)先記錄一個(gè)版本號(hào),,在提交事務(wù)時(shí),會(huì)檢查版本號(hào)是否變更,,從而作出判斷放棄或者重試,。

對于一個(gè)高并發(fā)的應(yīng)用程序來說,數(shù)據(jù)庫常常會(huì)成為一個(gè)訪問的瓶頸,,這里面主要存在以下的幾種訪問情況:

(1)讀讀并發(fā)

(2)讀寫并發(fā)

(3)寫寫并發(fā)

一般情況下,,數(shù)據(jù)庫都會(huì)有讀共享寫?yīng)氄嫉逆i并發(fā)的方案,也就是說讀讀并發(fā)是沒問題的,,但在讀寫并發(fā)時(shí),,則有可能出現(xiàn)讀取不一致情況,也就是常說的臟讀,,所以在悲觀鎖的模式下,,在有寫線程的時(shí)候,是不允許有任何其他的讀和寫線程的,,也就是說寫是獨(dú)占的,,這樣會(huì)導(dǎo)致系統(tǒng)的吞吐明顯下降,如何避免這一情況,,于是就出現(xiàn)了基于MVCC多版本控制并發(fā)的策略,,在這種策略下讀寫并發(fā)是可以同時(shí)進(jìn)行的,底層的原理是當(dāng)前有并發(fā)的寫線程在獨(dú)占,,那么讀線程就直接讀取事務(wù)log里面的歷史最新版本的數(shù)據(jù),,這樣以來就大大提高了并發(fā)吞吐能力,雖然讀取的數(shù)據(jù)并不是最新的數(shù)據(jù),,但是歷史上最新的,,同時(shí)也保持了一致性,目前主流的數(shù)據(jù)庫都支持這種模式,。最后一種是寫寫并發(fā)場景,,這種場景通常基于樂觀鎖的并發(fā)寫方案也稱OCC,,多個(gè)并發(fā)的寫線程,,每個(gè)線程都不會(huì)修改原始數(shù)據(jù),而是從原始數(shù)據(jù)上拷貝上一份數(shù)據(jù),,同時(shí)記錄版本號(hào),,不同的線程更新自己的數(shù)據(jù),在最終寫會(huì)時(shí)會(huì)判斷版本號(hào)是否變更,,如果變更則意味有人已經(jīng)更改過了,,那么當(dāng)前線程需要做的就是自旋重試,,如果重試指定的次數(shù)依然失敗,那么就應(yīng)該放棄更新,,這種策略僅僅適合寫并發(fā)并不強(qiáng)烈的場景,,如果寫競爭嚴(yán)重,那么多次自旋重試的開銷也是非常耗性能的,,如果競爭激烈,,那么寫鎖獨(dú)占的方式則更加適合。

基于上面談到的這些內(nèi)容,,我們再來分析StampedLock類,,就會(huì)非常比較容易理解,它實(shí)際主要解決的是讀寫并發(fā)場景更加類似于上面我們談到的MVCC的模式,。

StampedLock類有三種模式:

(一)寫鎖,,這里的寫鎖是獨(dú)占和排它的,,這里對于申請寫鎖成功的線程會(huì)得到一個(gè)stamp,,在釋放鎖unlockWrite(long)的時(shí)候會(huì)傳入這個(gè)票據(jù),申請寫鎖還支持非阻塞模式的調(diào)用通過tryWriteLock方法或者可超時(shí)的申請,,處于寫鎖狀態(tài)下,,任何其他的寫鎖,讀鎖,,樂觀讀鎖都會(huì)失敗,。

(二)讀鎖,申請成功會(huì)返回一個(gè)票據(jù),,同理在釋放的時(shí)候unlockRead(long)也需要傳回票據(jù),。讀鎖是共享的,前提是沒有任何寫鎖占用,。

(三)樂觀讀鎖,,是新的特性,這種策略非常輕量級(jí),,在操作數(shù)據(jù)時(shí)候并沒有使用CAS來設(shè)置鎖的狀態(tài),,如果當(dāng)前沒有線程持有寫鎖,那么樂觀讀鎖就會(huì)立即返回一個(gè)非0的票據(jù),,在獲得之后,,為了保持一致性,要拷貝需要使用的相關(guān)數(shù)據(jù)到線程的的棧里面,,然后再次判斷票據(jù)是否有效,,如果無效,則意味著這期間有線程修改了數(shù)據(jù)狀態(tài),,所以這時(shí)候要么放棄操作,,要么直接申請讀鎖,如果票據(jù)有效則意味著,當(dāng)前的數(shù)據(jù)沒有被更改過,,可能不是最新的,,但是一致的,在讀寫并發(fā)時(shí)候,,用來讀取是沒有問題的,,所以效率會(huì)高很多,因?yàn)闆]有使用任何的加鎖操作,,我們可以理解讀取的數(shù)據(jù)類似MVCC的快照,,最多不是最新的,但一定是一致的,。

StampedLock類的主要特點(diǎn),,我認(rèn)為有兩個(gè):

(1)通過樂觀讀鎖支持讀寫并發(fā),這里使用的是票據(jù)對比,。

(2)支持讀鎖升級(jí)成寫鎖

下面我們看一下官網(wǎng)給出的例子,,分別展示了寫鎖,樂觀讀鎖和讀鎖升級(jí)成寫鎖的案例:

  1. class Point {

  2.    // 成員變量

  3.    private double x, y;

  4.    // 鎖實(shí)例

  5.    private final StampedLock sl = new StampedLock();

  6.    // 排它鎖-寫鎖(writeLock)

  7.    void move(double deltaX, double deltaY) {

  8.        long stamp = sl.writeLock();

  9.        try {

  10.            x += deltaX;

  11.            y += deltaY;

  12.        } finally {

  13.            sl.unlockWrite(stamp);

  14.        }

  15.    }

  16.    // 樂觀讀鎖(tryOptimisticRead)

  17.    double distanceFromOrigin() {

  18.        // 嘗試獲取樂觀讀鎖(1)

  19.        long stamp = sl.tryOptimisticRead();

  20.        // 將全部變量拷貝到方法體棧內(nèi)(2)

  21.        double currentX = x, currentY = y;

  22.        // 檢查在(1)獲取到讀鎖票據(jù)后,,鎖有沒被其他寫線程排它性搶占(3)

  23.        if (!sl.validate(stamp)) {

  24.            // 如果被搶占則獲取一個(gè)共享讀鎖(悲觀獲?。?)

  25.            stamp = sl.readLock();

  26.            try {

  27.                // 將全部變量拷貝到方法體棧內(nèi)(5)

  28.                currentX = x;

  29.                currentY = y;

  30.            } finally {

  31.                // 釋放共享讀鎖(6)

  32.                sl.unlockRead(stamp);

  33.            }

  34.        }

  35.        // 返回計(jì)算結(jié)果(7)

  36.        return Math.sqrt(currentX * currentX + currentY * currentY);

  37.    }

  38.    // 讀鎖升級(jí)成寫鎖

  39.    void moveIfAtOrigin(double newX, double newY) {

  40.        // 這里可以使用樂觀讀鎖替換(1)

  41.        long stamp = sl.readLock();

  42.        try {

  43.            // 如果當(dāng)前點(diǎn)在原點(diǎn)則移動(dòng)(2)

  44.            while (x == 0.0 && y == 0.0) {

  45.                // 嘗試將獲取的讀鎖升級(jí)為寫鎖(3)

  46.                long ws = sl.tryConvertToWriteLock(stamp);

  47.                // 升級(jí)成功,則更新票據(jù),,并設(shè)置坐標(biāo)值,,然后退出循環(huán)(4)

  48.                if (ws != 0L) {

  49.                    stamp = ws;

  50.                    x = newX;

  51.                    y = newY;

  52.                    break;

  53.                } else {

  54.                    // 讀鎖升級(jí)寫鎖失敗則釋放讀鎖,顯示獲取獨(dú)占寫鎖,,然后循環(huán)重試(5)

  55.                    sl.unlockRead(stamp);

  56.                    stamp = sl.writeLock();

  57.                }

  58.            }

  59.        } finally {

  60.            // 釋放鎖(6)

  61.            sl.unlock(stamp);

  62.        }

  63.    }

  64. }

總結(jié):

本文主要介紹了JDK8里面新增的并發(fā)工具類StampedLock,,相比ReentrantLock重入鎖提供了更好的性能,并且支持讀寫并發(fā)的場景和讀鎖升級(jí)成寫鎖的功能,,在使用時(shí)候一定注意樂觀讀鎖需要先獲取票據(jù),,然后在拷貝實(shí)例數(shù)據(jù)到線程棧,然后接著判斷票據(jù)是否有效,,如果位置搞反,,那么則有可能使用出錯(cuò),這一點(diǎn)需要注意,。最后我們還要記住StampedLock是不支持重入的,,盡管你可以通過鎖轉(zhuǎn)換來變相實(shí)現(xiàn),還有對于StampedLock鎖這里并沒有明確強(qiáng)調(diào)公平和非公平的概念,,這里StampedLock會(huì)盡量保證最好的性能,。

https://docs.oracle.com/javase/8/docs/api/

https://www.jianshu.com/p/481071ddafd3

https://netjs./2016/08/stampedlock-in-java.html


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多