Golang中的锁机制主要包括两类:互斥锁(sync.Mutex)和读写锁(sync.RWMutex)。互斥锁用于保护共享资源的独占访问,而读写锁则允许多个读操作同时进行,但只允许一个写操作。
下面是一个互斥锁的使用示例:
package main
import (
"fmt"
"sync"
)
var (
counter int
mutex sync.Mutex
wg sync.WaitGroup
)
func main() {
// 启动10个goroutine去增加计数器
for i := 0; i < 10; i++ {
wg.Add(1)
go increment()
}
// 等待所有goroutine完成
wg.Wait()
fmt.Println("Final counter:", counter)
}
func increment() {
defer wg.Done()
// 对共享资源加锁
mutex.Lock()
defer mutex.Unlock()
// 对计数器加1
counter++
fmt.Println("Counter:", counter)
}
这个示例中,我们定义了一个全局的计数器和一个互斥锁。然后启动10个goroutine,每个goroutine都会尝试对计数器进行加1操作。但由于对计数器的访问是独占的,我们需要在对计数器进行修改之前对其加锁,以防止其他goroutine同时访问导致数据出错。
在 `increment` 函数中,我们使用 `mutex.Lock()` 和 `mutex.Unlock()` 将对共享资源的操作加锁和解锁。注意,在加锁之后,我们使用了 defer 语句来确保在函数结束时自动解锁,以防止程序在执行期间由于某种原因而无法解锁,从而导致死锁。
在主函数中,我们启动了10个goroutine,并等待它们都完成后再输出计数器的最终值。这里使用了 `sync.WaitGroup` 来实现等待所有goroutine完成的功能。
下面是一个读写锁的使用示例:
package main
import (
"fmt"
"sync"
"time"
)
var (
value int
rwMutex sync.RWMutex
wg sync.WaitGroup
)
func main() {
wg.Add(3)
// 启动3个goroutine进行读操作
for i := 0; i < 3; i++ {
go read(i+1)
}
// 启动一个goroutine进行写操作
go write(4)
wg.Wait()
}
func read(id int) {
defer wg.Done()
// 对读锁进行操作
rwMutex.RLock()
defer rwMutex.RUnlock()
fmt.Printf("Reader %d: %d\n", id, value)
time.Sleep(time.Second)
}
func write(id int) {
defer wg.Done()
// 对写锁进行操作
rwMutex.Lock()
defer rwMutex.Unlock()
value = 100
fmt.Printf("Writer %d: set value to %d\n", id, value)
time.Sleep(time.Second)
}
在这个示例中,我们定义了一个全局变量 `value` 和一个读写锁 `rwMutex`,并且启动了3个goroutine进行读操作和一个goroutine进行写操作。
在读操作中,我们用 `rwMutex.RLock()` 和 `rwMutex.RUnlock()` 对读锁进行加锁和解锁。由于我们使用的是读锁,因此多个goroutine可以同时读取该变量的值,而不会互相干扰。
在写操作中,我们用 `rwMutex.Lock()` 和 `rwMutex.Unlock()` 对写锁进行加锁和解锁。由于我们使用的是写锁,因此在写操作进行时,其他goroutine不能对该变量进行读或写操作。
在主函数中,我们启动了3个goroutine进行读操作和一个goroutine进行写操作。注意,在这里我们使用的是 `sync.WaitGroup` 保证所有goroutine都执行完毕后程序才结束。