java和Go在可重入鎖上的對比
面試提到有關go是如何實作可重入鎖的,都不太記得go有這個,記錄下
-
可重入鎖的概念:指的是同一個執行緒外層函式獲得鎖之后,內層遞回函式仍然能獲取該鎖的代碼,在同一個執行緒在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖,
-
java的可重入鎖:Java直接展示結果,是可以運行的,類似的代碼結構在golang中會出現 競爭例外(java的synchronized也是可重入結構)

-
go的鎖是否是可重入的
type Reentrant struct { sync.Mutex } func (receiver *Reentrant) methodA() { receiver.Lock() fmt.Println("method A is running") receiver.methodB() receiver.Unlock() } func (receiver Reentrant) methodB() { receiver.Lock() fmt.Println("method B is running") receiver.Unlock() } func TestReentrant(t *testing.T) { a := new(Reentrant) a.methodA() }
-
go實習一個簡單的可重入鎖
關于可重入鎖的原理,需要存盤的資訊包括鎖定狀態(需要注意狀態設定的原子性),持有鎖的執行緒,以及重入的次數,其中針對go來說獲取執行緒編號存在問題import ( "fmt" "runtime" "strconv" "strings" "sync" "sync/atomic" ) type MyReentrantLock struct { lock sync.Mutex id int counter int32 } func (l *MyReentrantLock) Lock() { // 第一次鎖 if atomic.CompareAndSwapInt32(&(l.counter), 0, 1){ l.lock.Lock() l.id = GoID() }else { if GoID() == l.id{ atomic.AddInt32(&(l.counter), 1) }else { // 這里就是阻塞goroutine了 l.lock.Lock() } } } func (l *MyReentrantLock) Unlock() { // 當counter歸零是真正釋放鎖 v := atomic.LoadInt32(&(l.counter)) if v == 0{ panic("this mutex is not locked") } if l.id == GoID(){ v := atomic.AddInt32(&(l.counter), -1) if v == 0 { l.lock.Unlock() } } } func GoID() int { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } return id }
參考鏈接
- 對可重入鎖和不可重入鎖的理解,他們的區別及實作原理決議
- 如何獲取goroutine id
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/252189.html
標籤:區塊鏈
上一篇:go mod模式下參考本地包/模塊(module)的方法
下一篇:第八十九周學習生活總結
