发布时间:2024-12-22 19:59:16
在并发编程中,锁是一种常用的机制,用于保护共享资源不被多个线程同时修改。对于Golang开发者来说,对锁的理解和使用是非常重要的。本文将深入探讨Golang中的锁以及与之相关的面试题目。
在Golang中,常用的锁有两种类型:互斥锁(Mutex)和读写锁(RWMutex)。互斥锁用于保护共享资源的互斥访问,即同一时间只允许一个线程对共享资源进行读写操作。而读写锁则提供了更灵活的读写策略,允许多个线程同时读取共享资源,但只允许一个线程进行写操作。
在使用锁的过程中,需要注意以下几点:
互斥锁是最基本的锁类型,在Golang中通过sync包提供的Mutex类型实现。下面是一个关于互斥锁的面试题目:
问题:下面的代码有没有问题?如果有问题,应该如何修改?
package main
import (
"fmt"
"sync"
)
var m sync.Mutex
var counter = 0
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
m.Lock()
counter++
m.Unlock()
wg.Done()
}()
}
wg.Wait()
fmt.Println("counter:", counter)
}
答案:上述代码存在问题,因为counter变量可能会被多个goroutine同时修改,从而导致数据竞争。为了解决这个问题,可以使用互斥锁将对counter的修改操作变为互斥的。修改后的代码如下:
package main
import (
"fmt"
"sync"
)
var m sync.Mutex
var counter = 0
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
m.Lock()
counter++
m.Unlock()
wg.Done()
}()
}
wg.Wait()
fmt.Println("counter:", counter)
}
读写锁是一种更高级的锁类型,在Golang中通过sync包提供的RWMutex类型实现。下面是一个关于读写锁的面试题目:
问题:下面的代码有没有问题?如果有问题,应该如何修改?
package main
import (
"fmt"
"sync"
)
var rw sync.RWMutex
var counter = 0
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
rw.Lock()
counter++
rw.Unlock()
wg.Done()
}()
}
wg.Wait()
fmt.Println("counter:", counter)
}
答案:上述代码存在问题,因为读写锁应该用于保护共享资源的读写操作,但是在上述代码中,我们仅仅对counter进行了写操作,并没有进行任何读操作。因此,上述代码中使用读写锁是不合适的。如果要修复这个问题,可以将互斥锁替换为普通的互斥锁(Mutex)。修改后的代码如下:
package main
import (
"fmt"
"sync"
)
var m sync.Mutex
var counter = 0
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
m.Lock()
counter++
m.Unlock()
wg.Done()
}()
}
wg.Wait()
fmt.Println("counter:", counter)
}
在并发编程中,死锁是一个非常常见的问题。下面是一个关于死锁的面试题目:
问题:下面的代码有没有问题?如果有问题,应该如何修改?
package main
import (
"fmt"
"sync"
)
var m1 sync.Mutex
var m2 sync.Mutex
func main() {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
m1.Lock()
m2.Lock()
fmt.Println("goroutine 1")
m1.Unlock()
m2.Unlock()
wg.Done()
}()
go func() {
m2.Lock()
m1.Lock()
fmt.Println("goroutine 2")
m2.Unlock()
m1.Unlock()
wg.Done()
}()
wg.Wait()
}
答案:上述代码存在死锁问题。死锁的原因是两个goroutine互相等待对方释放锁。为了解决这个问题,可以使用多个锁的顺序一致性原则,即按照指定的顺序获得和释放锁。修改后的代码如下:
package main
import (
"fmt"
"sync"
)
var m1 sync.Mutex
var m2 sync.Mutex
func main() {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
m1.Lock()
m2.Lock()
fmt.Println("goroutine 1")
m2.Unlock()
m1.Unlock()
wg.Done()
}()
go func() {
m1.Lock()
m2.Lock()
fmt.Println("goroutine 2")
m2.Unlock()
m1.Unlock()
wg.Done()
}()
wg.Wait()
}
通过上述修改,保证了goroutine 1和goroutine 2获取锁的顺序一致,解决了死锁问题。