GO语言基础教程(155)Go活锁:Go语言中的活锁:你的代码在跳舞,却从未前进?

那个看似忙碌但一无所成的并发任务,可能正陷入活锁的漩涡

什么是活锁?从生活中的例子说起

想象一下,你在一条狭窄的走廊里走向对面而来的人。她移动到一边让你通过,但你也做了同样的动作。所以你转移到另一边,她也是这样做的。如此反复,你们就像在跳一场没有尽头的舞蹈,却始终无法通过。

活锁就是:任务或执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试、失败、再尝试、再失败。在Go语言中,活锁指的是程序一直在运行,但是无法取得进展。

与死锁不同,活锁的实体是在不断地改变状态,所谓的"活",而处于死锁的实体表现为等待。活锁有可能自行解开,死锁则不能。

活锁 vs 死锁:关键区别

为了更好地理解活锁,让我们先弄清楚它和死锁的区别:

死锁就像两个司机在一条单行道上迎面停车,谁也不肯后退,就这样永远僵持下去。而死锁是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

活锁则像两个过于礼貌的人在门口相遇:每个人都坚持让对方先走,你向左我也向左,你向右我也向右,结果还是堵在门口。虽然双方都在不断运动,但谁也无法通过。

在技术层面上,活锁应该是一系列进程在轮询地等待某个不可能为真的条件为真。活锁的时候进程是不会blocked,这会导致耗尽CPU资源。

Go语言中的活锁实例

让我们来看一个具体的Go代码示例,它演示了活锁是如何发生的:

package main

import (
  "fmt"
  "sync"
)

func main() {
  var wg sync.WaitGroup
  var mu sync.Mutex
  var flag bool

  wg.Add(2)

  // goroutine 1
  go func() {
    // 先获取锁资源
    fmt.Println("goroutine 1 获取 mu")
    mu.Lock()
    defer mu.Unlock()

    // 然后等待 flag 变量的值变为 true
    fmt.Println("goroutine 1 等待标志")
    for !flag {
      // 不断循环等待
    }

    // 最终输出并释放锁资源
    fmt.Println("goroutine 1 从等待中释放")
    wg.Done()
  }()

  // goroutine 2
  go func() {
    // 先获取锁资源
    fmt.Println("goroutine 2 获取 mu")
    mu.Lock()
    defer mu.Unlock()

    // 然后等待 flag 变量的值变为 true
    fmt.Println("GoRoutine2 等待标志")
    for !flag {
      // 不断循环等待
    }

    // 最终输出并释放锁资源
    fmt.Println("G
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值