Udemy Course Multithreading, Concurrency & Performance 27

Semaphore(Producer & Consumer)Lock

ZONGRU Li
Sep 18, 2021

前面課程大多是針對單一個Resource的Lock介紹

接著介紹如果有N個可利用的Resources的狀況

— Semaphore Lock(實際使用上code稍微複雜,可參考下面範例解說)

就如停車場有8個車位,當有8台車將位置停滿

第9台車進來後就需要等待位置空出來

只要8個中任意個位置空出來(有一台車離開),這第9台車就可以補位進去

基本寫法如下:

甚至可以一次佔據複數的Resource

Semaphore Lock與其他Lock的不同之處要注意!

  1. Semaphore不具有Lock持有者概念

一般Lock(非Semaphore)使用下,A Thread鎖的只能由A Thread解鎖

Semaphore Lock則是B Thread可以去替A Thread鎖住的做解鎖

2.一堆Threads都能去做Semaphore.acquire()

3.單一個Thread甚至可以多次地Semaphore.acquire() x N

4.以上可得結論:二進位的Semaphore初始數量1 不等同reentrant

5.任何Thread都可release Semaphore,甚至沒在跑acquire的Thread都可以

接著往下

上述狀況在其他的Lock(非Semaphore)就不會發生

因為其他Lock只有鎖住的Thread可以release

綜上特性

所以Semaphore Lock其實最適合應用於副標題上Producer & Consumer狀況

以下圖示特殊執行方式來展示Semaphore Lock特性

考量有兩個Semaphore鎖,及一個item Resource物件

同一時間右邊的consumer醒來往下執行

此時若Producer早一步進到下一輪則會

如上兩邊(Consumer 及 Producer)往復循環

但是當Consumer是跑比較快的話:

那麼大部分時間將是Consumer卡在full.acquire();

這狀況下因為沒有進到consumer(item),所以不太消耗CPU

但是當Consumer是跑比較慢的話:

那麼大部分時間將是Producer卡在empty.acquire();

並且等待Consumer執行完消耗item後釋放empty

整體運作大致如下:

並且只要小小修改後也支援複數個Producer,及複數個Consumer如下

1.首先更改被鎖的Resource為Queue(由Queue統一提供Resource item)

並訂定Queue的容許量為CAPACITY

為了保護Queue內的Resource item被太多Consumer & Producer消耗

另外建立一般的Lock(這邊簡單選用Reentrant Lock)

並改造Producer產生Resource item後交給Queue

上圖Producer直接產出Resource item後

提供給queue(執行queue.offer(item))

但是queue要保持一致性,所以queue.offer前後要lock起來(用普通lock即可)

而Consumer則如下

上圖Consumer確定拿到item後,亦即這個item就可以隨意消耗了

所以consumer(item)前後不用鎖

以上即改造完成!

同樣的概念也廣泛的應用在其他系統環節,例如TCP溝通等

確保有足夠的channel才能連線後做後續處理等

參考課程

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet