Go语言并发安全与锁

有时候在Go语言代码中可能会存在多个goroutine同时操作一个资源的情况,这种时候就会发生竞态问题(数据竞态),go语言可以使用互斥锁来解决这个问题,互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源,可以使用sync包的Mutex类型来实现互斥锁,其他的goroutine则在等待锁,当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒的策略是随机的,下面是一个例子,如果没有加锁那么最终的结果是错误的,其实就是线程安全问题,多个线程同时对全局变量进行修改这样就会影响另外的线程:

package main

import (
	"fmt"
	"sync"
)

var x int64
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
	for i := 0; i < 5000000; i++ {
		lock.Lock() // 加锁
		x = x + 1
		lock.Unlock() // 解锁
	}
	wg.Done()
}

func main() {
	wg.Add(2)
	go add()
	go add()
	wg.Wait()
	fmt.Println(x)
}

读写互斥锁

互斥锁是完全互斥的,但是有很多时候是读多写少的,当我们并发的去读取一个资源不涉及资源修改的时候没有必要加锁,所以这种情况下使用读写锁是更好的一种选择,在Go语言中可以使用sync包中的RWMutex类型,读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待,当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待,下面是一个例子:

package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	x      int64
	wg     sync.WaitGroup
	rwlock sync.RWMutex
)

func write() {
	rwlock.Lock() // 加写锁
	x = x + 1
	time.Sleep(10 * time.Millisecond) // 假设读操作耗时10毫秒
	rwlock.Unlock()                   // 解写锁
	wg.Done()
}

func read() {
	rwlock.RLock()               // 加读锁
	time.Sleep(time.Millisecond) // 假设读操作耗时1毫秒
	rwlock.RUnlock()             // 解读锁
	wg.Done()
}

func main() {
	start := time.Now()
    // 使用go关键字启动10个写的协程
	for i := 0; i < 10; i++ {
		wg.Add(1)
		// 启动一个协程
		go write()
	}
    // 使用go关键字启动1000个读的协程
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go read()
	}

	wg.Wait()
	end := time.Now()
	fmt.Println(end.Sub(start))
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值