package main
import (
"fmt"
"sync"
)
var counter int
var mutex sync.Mutex
func worker(wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 1000; i++ {
mutex.Lock() // 获取锁
counter++ // 临界区:访问共享变量
mutex.Unlock() // 释放锁
}
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
fmt.Println("Counter:", counter) // 输出:Counter: 5000
}
说明:
使用 sync.Mutex 锁定共享资源访问。
counter 在多个 goroutine 并发执行时是安全的,最终输出结果为 5000。
2. sync.RWMutex - 读写锁
作用 :区分读和写的操作:
多个 goroutine 可以同时读取(并发读)。
写操作会独占锁(互斥写),阻塞其他读和写操作。
方法 :
RLock() / RUnlock():获取/释放读锁。
Lock() / Unlock():获取/释放写锁。
示例代码:
go复制代码
package main
import (
"fmt"
"sync"
"time"
)
var data int
var rwMutex sync.RWMutex
func readData(id int, wg *sync.WaitGroup) {
defer wg.Done()
rwMutex.RLock()
fmt.Printf("Reader %d: Read data %d\n", id, data)
time.Sleep(time.Millisecond * 10)
rwMutex.RUnlock()
}
func writeData(id int, wg *sync.WaitGroup) {
defer wg.Done()
rwMutex.Lock()
data += 1
fmt.Printf("Writer %d: Wrote data %d\n", id, data)
time.Sleep(time.Millisecond * 10)
rwMutex.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go writeData(i, &wg) // 写操作
}
for i := 1; i <= 5; i++ {
wg.Add(1)
go readData(i, &wg) // 读操作
}
wg.Wait()
}
说明:
读写锁允许多个读操作同时进行,但写操作是独占的,其他读写操作会被阻塞。
3. sync.WaitGroup - 等待组
作用:用于等待一组 goroutine 完成。
方法 :
Add(n):增加等待的 goroutine 计数。
Done():完成一个 goroutine 的计数。
Wait():阻塞,直到计数为 0。
示例代码:
go复制代码
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d is working\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers finished")
}
说明:
wg.Add(1) 表示增加一个等待的 goroutine。
defer wg.Done() 表示 goroutine 完成时减少计数。
wg.Wait() 阻塞主线程,直到所有计数为 0。
4. sync.Once - 单次执行
作用 :确保某个操作(如初始化)只执行一次,常用的 close channel 。
方法 :
Do(f func()):只会执行一次 f,无论有多少个 goroutine 调用。
示例代码:
go复制代码
package main
import (
"fmt"
"sync"
)
var once sync.Once
func initialize() {
fmt.Println("Initializing...")
}
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
once.Do(initialize) // 确保 initialize 只执行一次
fmt.Printf("Worker %d is working\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}