欢迎加入GolangRoadmap,一个年轻的GO开发者社区https://www.golangroadmap.com/,目前是邀请制注册,注册码:Gopher-1035-0722,已开放Golang岗位内推,Golang企业题库,Golang精品资源等栏目
以下题目资源都来自GolangRoadmap->Go求职->企业题库
题目ID-1 Mutex 几种状态
- mutexLocked — 表示互斥锁的锁定状态
- mutexWoken — 表示从正常模式被从唤醒
- mutexStarving — 当前的互斥锁进入饥饿状态
- waitersCount — 当前互斥锁上等待的 Goroutine 个数
题目ID-2 Mutex 几种状态
-
正常模式(非公平锁)正常模式下,所有等待锁的 goroutine 按照 FIFO(先进先出)顺序等待。唤醒的 goroutine不会直接拥有锁,而是会和新请求 goroutine 竞争锁。新请求的 goroutine 更容易抢占:因为它正在 CPU上执行,所以刚刚唤醒的goroutine有很大可能在锁竞争中失败。在这种情况下,这个被唤醒的 goroutine 会加入到等待队列的前面。
-
饥饿模式(公平锁)为了解决了等待 goroutine 队列的长尾问题,饥饿模式下,直接由 unlock 把锁交给等待队列中排在第一位的goroutine (队 头),同时,饥饿模式下,新进来的 goroutine 不会参与抢锁也不会进入自旋状态,会直接进入等待队列的尾部。这样很好的解决了老的 goroutine 一直抢不到锁的场景。 饥饿模式的触发条件:当一个goroutine 等待锁时间超过 1 毫秒时,或者当前 队列只剩下一个 goroutine 的时候,Mutex 切换到饥饿模式。
-
总结:对于两种模式,正常模式下的性能是最好的,goroutine 可以连续多次获取锁,饥饿模式解决了取锁公平的问题,但是性能会下降,这其实是性能和公平的一个平衡模式。
补充:自旋锁
自旋锁是指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断地判断是否能够被成功获取,知直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。
它是为实现保护共享资源而提出的一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能由一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,“自旋”一词就是因此而得名。