成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

Java 重入鎖和讀寫鎖的具體使用

瀏覽:3日期:2022-08-15 14:38:04
重入鎖

重入鎖 ReentrantLock,顧名思義,就是支持重進入的鎖,它表示該鎖能夠支持一個線程對資源的重復加鎖。除此之外,該鎖還支持獲取鎖時的公平和非公平性選擇

所謂不支持重進入,可以考慮如下場景:當一個線程調(diào)用 lock() 方法獲取鎖之后,如果再次調(diào)用 lock() 方法,則該線程將會被自己阻塞,原因是在調(diào)用 tryAcquire(int acquires) 方法時會返回 false,從而導致線程阻塞

synchronize 關鍵字隱式的支持重進入,比如一個 synchronize 修飾的遞歸方法,在方法執(zhí)行時,執(zhí)行線程在獲取鎖之后仍能連續(xù)多次地獲得該鎖。ReentrantLock 雖然不能像 synchronize 關鍵字一樣支持隱式的重進入,但在調(diào)用 lock() 方法時,已經(jīng)獲得鎖的線程,能夠再次調(diào)用 lock() 方法獲取鎖而不被阻塞

1. 實現(xiàn)重進入

重進入特性的實現(xiàn)需要解決以下兩個問題:

線程再次獲取鎖鎖需要去識別獲取鎖的線程是否為當前占據(jù)鎖的線程,如果是,則再次成功獲取

鎖的最終釋放線程重復 n 次獲取鎖,隨后在第 n 次釋放該鎖后,其他線程能獲取到鎖。實現(xiàn)此功能,理應考慮使用計數(shù)

ReentrantLock 通過組合自定義同步器來實現(xiàn)鎖的獲取與釋放,以非公平鎖實現(xiàn)為例,獲取同步狀態(tài)的代碼如下所示,主要是增加了再次獲取同步狀態(tài)的處理邏輯

final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 判斷當前線程是否為獲取鎖的線程 else if (current == getExclusiveOwnerThread()) { // 將同步值進行增加,并返回 true int nextc = c + acquires; if (nextc < 0) throw new Error('Maximum lock count exceeded'); setState(nextc); return true; } return false;}

考慮到成功獲取鎖的線程再次獲取鎖,只是增加同步狀態(tài)值,這也就要求 ReentrantLock 在釋放同步狀態(tài)時減少同步狀態(tài)值,該方法代碼如下:

protected final boolean tryRelease(int releases) { // 減少狀態(tài)值 int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 當同步狀態(tài)為0,將占有線程設為null,并返回true,表示釋放成功 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free;}2. 公平與非公平獲取鎖的區(qū)別

如果一個鎖是公平的,那么鎖的獲取順序就應該符合請求的絕對時間順序,也即 FIFO。回顧上一節(jié),非公平鎖只要 CAS 設置同步狀態(tài)成功,即表示當前線程獲取了鎖,而公平鎖則不同,代碼如下:

protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { /* * 唯一不同的就是判斷條件多了 hasQueuedPredecessors() * 該方法用來判斷當前節(jié)點是否有前驅(qū)節(jié)點 * 如果該方法返回 true,表示有線程比當前線程更早請求獲取鎖 * 因此需要等待前驅(qū)線程釋放鎖之后才能繼續(xù)獲取鎖 */ if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error('Maximum lock count exceeded'); setState(nextc); return true; } return false;}讀寫鎖

之前提到的鎖基本都是排它鎖,同一時刻只允許一個線程訪問,而讀寫鎖在同一時刻可以允許多個線程訪問,但在寫線程訪問時,所有的讀線程和其他寫線程均被阻塞。讀寫鎖維護了一對鎖,一個讀鎖和一個寫鎖,通過分離讀鎖和寫鎖,使得并發(fā)性相比一般的排它鎖有了很大提升

1. 接口示例

下面通過緩存示例說明讀寫鎖的使用方式

public class Cache { static Map<String, Object> map = new HashMap<>(); static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); static Lock r = rwl.readLock(); static Lock w = rwl.writeLock(); /** * 獲取一個 key 對應的 value */ public static Object get(String key) { r.lock(); try { return map.get(key); } finally { r.unlock(); } } /** * 設置 key 對應的 value,并返回舊的 value */ public static Object put(String key, Object value) { w.lock(); try { return map.put(key, value); } finally { w.unlock(); } } /** * 清空所有的內(nèi)容 */ public static void clear() { w.lock(); try { map.clear(); } finally { w.unlock(); } }}2. 讀寫狀態(tài)的設計

讀寫鎖同樣依賴自定義同步器來實現(xiàn)功能,而讀寫狀態(tài)就是其同步器狀態(tài)。讀寫鎖的自定義同步器需要在同步狀態(tài)(一個整型變量)上維護多個讀線程和一個寫線程的狀態(tài),為此需要讀寫鎖將變量切分成兩部分,高 16 位表示讀,低 16 位表示寫

Java 重入鎖和讀寫鎖的具體使用

上圖表示一個線程已經(jīng)獲取了寫鎖,且重進入了兩次,同時也連續(xù)兩次獲取了讀鎖。通過位運算可以迅速確定讀和寫各自的狀態(tài),假設當前同步狀態(tài)值為 S,則:

寫狀態(tài)等于 S & 0x0000FFFF(將高 16 位全部抹去) 讀狀態(tài)等于 S >>> 16(無符號右移 16 位) 當寫狀態(tài)增加 1 時,等于 S + 1 當讀狀態(tài)增加 1 時,等于 S + (1<<6),也就是 S + 0x00010000

根據(jù)狀態(tài)的劃分能得出一個結(jié)論:S 不等于 0 時,當寫狀態(tài)(S & 0x0000FFFF)等于 0 時,則讀狀態(tài)(S >>> 16)大于 0,即讀鎖已被獲取

3. 寫鎖的獲取與釋放

寫鎖是一個支持重進入的排它鎖。如果當前線程已經(jīng)獲取了寫鎖,則增加寫狀態(tài)。如果當前線程在獲取寫鎖時,讀鎖已被獲取,或者該線程不是獲取寫鎖的線程,則當前線程進入等待狀態(tài),獲取寫鎖的代碼如下:

protected final boolean tryAcquire(int acquires) { Thread current = Thread.currentThread(); int c = getState(); // exclusiveCount 方法會用 c & 0x0000FFFF,即得出寫狀態(tài)個數(shù) int w = exclusiveCount(c); if (c != 0) { // 根據(jù)上面提到的推論,c 不等于 0,而 w 等于 0,證明存在讀鎖 // 當前線程也不是獲取了寫鎖的線程 if (w == 0 || current != getExclusiveOwnerThread()) return false; if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error('Maximum lock count exceeded'); setState(c + acquires); return true; } if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false; setExclusiveOwnerThread(current); return true;}

寫鎖的每次釋放均會減少寫狀態(tài),當寫狀態(tài)為 0 時表示寫鎖已被釋放,從而等待的讀寫線程能夠繼續(xù)訪問讀寫鎖,同時前次寫線程的修改對后續(xù)讀寫線程可見

4. 讀鎖的獲取與釋放

讀鎖是一個支持重進入的共享鎖,它能被多個線程同時獲取,在沒有其他寫線程訪問時,讀鎖總能被成功獲取,這里對獲取讀鎖的代碼做了簡化:

protected final int tryAcquireShared(int unused) { for(;;) { int c = getState(); int nextc = c + (1<<16); if(nextc < c) { throw new Error('Maximum lock count exceeded'); } // 如果其他線程已經(jīng)獲取寫鎖,則讀取獲取失敗 if(exclusiveCount(c) != 0 && owner != Thread.currentThread()) { return -1; } if(compareAndSetState(c, nextc)) { return 1; } }}

讀鎖的每次釋放均減少讀狀態(tài),減少的值是 1<<16

5. 鎖降級

鎖降級指的是寫鎖降級成為讀鎖。如果當前線程擁有寫鎖,然后將其釋放,最后再獲取讀鎖,這種分段完成的過程不能稱之為鎖降級。鎖降級是指把持住寫鎖,再獲取讀鎖,隨后釋放寫鎖的過程

public void processData() { readLock.lock(); if(!update) { // 必須先釋放讀鎖 readLock.unlock(); // 鎖降級從寫鎖獲取到開始 writeLock.lock(); try { if(!update) { // 準備數(shù)據(jù)的流程(略) update = true; } readLock.lock(); } finally { writeLock.unlock(); } } try { // 使用數(shù)據(jù)的流程(略) } finally { readLock.unlock(); }}

上例中,當數(shù)據(jù)發(fā)生變更,則 update(使用 volatile 修飾)被設置為 false,此時所有訪問 processData 方法的線程都能感知到變化,但只有一個線程能獲取到寫鎖,其余線程會被阻塞在寫鎖的 lock 方法上。當前線程獲取寫鎖完成數(shù)據(jù)準備之后,再次獲取讀鎖,隨后釋放寫鎖,完成鎖降級

到此這篇關于Java 重入鎖和讀寫鎖的具體使用的文章就介紹到這了,更多相關Java 重入鎖和讀寫鎖內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持好吧啦網(wǎng)!

標簽: Java
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
中国成人亚色综合网站| 日韩免费高清av| eeuss影院一区二区三区 | 国产精品美女久久福利网站| 午夜精品久久久久久久99水蜜桃| 成+人+亚洲+综合天堂| 在线播放91灌醉迷j高跟美女| 亚洲摸摸操操av| 欧美日韩视频在线一区二区观看视频| 欧美中文一区二区三区| 亚洲精品菠萝久久久久久久| 国v精品久久久网| 日韩一区二区三区四区五区六区| 亚洲图片有声小说| 亚洲三级电影在线观看| 国产精品免费久久| 国产精品一线二线三线| 欧美亚洲精品一区| 日韩精品乱码免费| 久久人人九九| 秋霞午夜av一区二区三区| 亚洲欧洲另类| 综合欧美一区二区三区| 在线欧美亚洲| 亚洲乱码国产乱码精品精小说| 成人激情开心网| 欧美一级爆毛片| 国产成人综合在线观看| 欧美在线观看一区| 久久国产精品第一页| 国产精品午夜av在线| 亚洲无人区一区| 日本精品一区二区三区高清| 美国三级日本三级久久99 | 精品国产乱子伦一区| 粉嫩一区二区三区性色av| 91精品国产欧美一区二区| 亚洲成人av一区二区三区| 麻豆成人小视频| 日本不卡一区二区三区高清视频| 欧美在线一二三区| 欧美国产乱子伦| 极品中文字幕一区| 亚洲麻豆国产自偷在线| 美女成人午夜| 久久国产精品99久久久久久老狼| 欧美日韩一区二| 欧美日韩五月天| 国产精品自拍三区| 久久综合国产精品| 欧美午夜精品| 亚洲免费观看高清完整版在线观看| 91丨porny丨户外露出| 日本久久一区二区| 国产精品一区二区男女羞羞无遮挡 | 亚洲成人综合网站| 久久久久se| 激情久久五月天| 久久精品在这里| 激情欧美日韩| 国产精品久久久久久久久晋中| 国v精品久久久网| 精品视频免费看| 国产成人精品一区二区三区四区 | 国产一区不卡在线| 国产亚洲成aⅴ人片在线观看| 福利电影一区二区| 亚洲国产成人一区二区三区| 91在线视频18| ●精品国产综合乱码久久久久| 99re在线视频这里只有精品| 国产精品福利一区二区| 免费亚洲婷婷| 国产成人久久精品77777最新版本 国产成人鲁色资源国产91色综 | 欧美v日韩v国产v| 欧美午夜一区| 中文字幕av一区二区三区高| 国产欧美日韩综合精品二区| 久久精品久久99精品久久| 欧美电影精品一区二区| 国内久久视频| 美腿丝袜亚洲综合| 久久久久国产免费免费| 国产日韩欧美一区二区三区在线观看 | 亚洲一级黄色| 美美哒免费高清在线观看视频一区二区 | 免费在线看成人av| 精品国产成人在线影院 | 在线观看免费亚洲| 成+人+亚洲+综合天堂| 一区二区三区波多野结衣在线观看| 一区二区国产日产| 一区二区三区四区激情| 欧美日韩一区成人| 欧美日韩精品久久| 17c精品麻豆一区二区免费| 亚洲特级毛片| 日韩和欧美一区二区三区| 精品美女在线观看| 六月婷婷一区| 91麻豆成人久久精品二区三区| 国产精品久久久久久久久果冻传媒 | av成人国产| 国产盗摄女厕一区二区三区| 亚洲图片你懂的| 91精品国产色综合久久不卡电影| 福利电影一区二区三区| 亚洲一区二区三区三| 欧美成人福利视频| 美女91精品| 欧美日韩国产三区| 精品一区二区免费| 国产精品对白交换视频| 51精品国自产在线| 国产精品毛片一区二区三区| 成人动漫中文字幕| 午夜日韩在线观看| 国产欧美日韩激情| 亚洲一卡久久| 天天影视网天天综合色在线播放| 欧美日韩一二区| 亚洲经典在线看| 成人国产免费视频| 亚洲欧美成人一区二区三区| 色吊一区二区三区| 好看的av在线不卡观看| 国产成人免费视| 日韩国产欧美在线播放| 日韩理论电影院| 久久久久久久网| 久久精品日产第一区二区| 国产在线乱码一区二区三区| 亚洲精品日日夜夜| 精品sm在线观看| 欧美日韩情趣电影| 亚洲一区二三| 黑人一区二区| av电影在线观看一区| 精品一区二区三区av| 五月综合激情网| 最好看的中文字幕久久| 久久久久久免费毛片精品| 91精品国产色综合久久ai换脸 | 18涩涩午夜精品.www| 精品少妇一区二区三区视频免付费| 在线精品在线| 欧美精选在线播放| 亚洲天堂偷拍| 99re66热这里只有精品3直播 | 国产欧美日韩一区二区三区| 91农村精品一区二区在线| 国产精品综合二区| 免费成人性网站| 亚洲风情在线资源站| 中文字幕中文字幕在线一区| 日韩精品一区二区三区视频播放| 亚洲欧洲三级| 欧美大香线蕉线伊人久久国产精品| 日韩精品91亚洲二区在线观看| 久久久91精品国产一区二区精品| 久久av一区二区三区亚洲| 国产一区二区三区四区老人| 99久久er热在这里只有精品15| 亚洲地区一二三色| 亚洲欧美另类小说| 国产人久久人人人人爽| 色狠狠桃花综合| 亚洲欧美日韩一区在线观看| 亚洲黄色一区| 激情亚洲成人| 国内综合精品午夜久久资源| 欧美777四色影| 欧美一区二区三区四区在线观看地址 | 成人精品高清在线| 国产一区二区电影| 九色综合狠狠综合久久| 久久99精品久久久久久动态图 | 久久精品av麻豆的观看方式| 日韩和欧美一区二区三区| 国产精品乱码一区二三区小蝌蚪| 欧美精选一区二区| 欧美日韩激情在线| 欧美精品在线一区二区| 欧美精品久久久久久久多人混战| 免费在线观看成人av| 国产一区二区三区黄| 亚洲一区二区三区精品视频| 午夜宅男欧美| 久久狠狠一本精品综合网| 久久亚洲精品欧美| 欧美艳星brazzers| 欧美在线观看视频一区二区 | 99视频一区| 91社区在线播放| 国产一区二区视频在线| 精品一区二区三区欧美| 国产真实乱对白精彩久久| 国产成人欧美日韩在线电影| www.久久精品| 欧美有码视频|