互斥锁与读写锁使用
来源:互联网 发布:数据交换共享 编辑:程序博客网 时间:2024/06/03 20:31
概述
sync.Mutex和sync.RWMutex是Go语言底层基础对象,用于构建多个goroutine间的同步逻辑,当多个协程需要对共享数据读写时用到。具体实现极为简洁,性能也有保证。
使用场景
举例:1.多个协程操作同一个文件 2.生产者消费者模型 具体实例我就以最简单的打印方式说明
代码
互斥锁func print(t *testing.T, i int, wg *sync.WaitGroup, mutex *sync.Mutex) { // mutex.Lock() t.Logf("routine i=%d start!", i) time.Sleep(time.Millisecond * 10) t.Logf("routine i=%d end!", i) wg.Done() // mutex.Unlock()}func TestSync(t *testing.T) { runtime.GOMAXPROCS(runtime.NumCPU()) var wg = new(sync.WaitGroup) var mutex = &sync.Mutex{} for i := 0; i < 2; i++ { wg.Add(1) go print(t, i, wg, mutex) } wg.Wait()}这是go的测试用例,并没有用main函数来执行,go的源码里面很多都是以这种形式写的测试用例。这里需要说明一下,go的协程需要达到真正的并发,需要加上runtime.GOMAXPROCS(runtime.NumCPU()),print函数里面mutex.Lock()注释了,打印的结果是 sync_test.go:12: routine i=0 start! sync_test.go:12: routine i=1 start! sync_test.go:14: routine i=1 end! sync_test.go:14: routine i=0 end!协程0(暂且这么称呼)先执行print函数,但并没有先结束,我们看到协程1是先结束的,这个程序就有并发安全性的问题。如果需要解决这个问题,达到谁先进入公共代码区域,谁就先结束,只需要把print函数里面互斥锁Lock()和Unlock()打开即可,会看到如下打印信息。 sync_test.go:12: routine i=0 start! sync_test.go:14: routine i=0 end! sync_test.go:12: routine i=1 start! sync_test.go:14: routine i=1 end!
读写锁验证结论:如果一个协程在读,其他协程不可以写,其他协程可以读。如果一个协程在写,任何协程都不可以读和写首先验证多个读func TestReadLock(t *testing.T) { lock := new(sync.RWMutex) go Read(lock, 1) //多个协程随便读,并不锁住 go Read(lock, 2) time.Sleep(time.Second * 4)}func Read(lock *sync.RWMutex, i int) { println(i, "read start") lock.RLock()//读锁定 defer lock.RUnlock()//读解锁 println(i, "reading") if i == 2 { time.Sleep(3 * time.Second) } else { time.Sleep(1 * time.Second) } println(i, "read end")}打印信息如下:1 read start2 read start1 reading2 reading1 read end2 read end我们可以看出,协程1在没有read完之前,协程2还是可以读的,即验证了可以有多个读这次来验证第二个结论,有一个协程在读,另个协程能不能写呢?func TestWriteLock(t *testing.T) { lock := new(sync.RWMutex) go Read(lock, 2) go Read(lock, 4) // time.Sleep(1 * time.Second) go Write(lock, 1) //如果在读,不可以写,可以读,如果在写,不可以写,不可以读 go Write(lock, 3) time.Sleep(10 * time.Second)}func Read(lock *sync.RWMutex, i int) { println(i, "read start") lock.RLock() defer lock.RUnlock() println(i, "reading") if i == 2 { time.Sleep(3 * time.Second) } else { time.Sleep(1 * time.Second) } println(i, "read end")}func Write(lock *sync.RWMutex, i int) { println(i, "write start") lock.Lock()//写锁定 defer lock.Unlock()//写解锁 println(i, "writing") time.Sleep(1 * time.Second) println(i, "write end")}打印如下:2 read start2 reading3 write start1 write start4 read start2 read end3 writing3 write end4 reading4 read end1 writing1 write end我们看到,协程2号线进入读,协程3号写开始,但并没有writing,而是等到协程2号read end之后才开始writing,协程2号在读的时候,协程4号开始读,但由于协程3号是在协程2号之后进入write start,所以协程2号read end后是协程3号writing,直到结束,协程4号开始reading接下来验证最后一个结论我们把TestWriteLock函数里面的Write协程放到前面func TestWriteLock(t *testing.T) { lock := new(sync.RWMutex) go Write(lock, 1) //如果在读,不可以写,可以读,如果在写,不可以写,不可以读 go Write(lock, 3) go Read(lock, 2) go Read(lock, 4) time.Sleep(10 * time.Second)}打印信息如下:1 write start1 writing4 read start2 read start3 write start1 write end2 reading4 reading4 read end2 read end3 writing3 write end好了,我们已经验证了我们最开始的结论,是不是很简单。
阅读全文
0 0
- 互斥锁与读写锁使用
- ReentrantReadWriteLock读写锁的理解与使用
- java线程:互斥锁与读写锁
- java线程:互斥锁与读写锁
- java线程:互斥锁与读写锁
- 10066--- java线程:互斥锁与读写锁
- 同步与读写锁
- 线程与读写锁
- 使用读写锁
- linux使用读写锁
- 使用读写锁
- 读写锁的使用
- 文件读写与NSInputStream的简单使用
- 使用FileReader与FileWriter读写数据
- 【C#】XML读写与dataGridView的使用
- 多线程读写数据方法之读写锁方法与shared_ptr+互斥锁方法的比较
- 嵌套锁与读写锁
- 读写锁与自旋锁
- 数据库存储过程和函数
- 在 JavaScript 中为什么 typeof null 的结果是 object?为什么呢?
- Nginx安装手册
- java-pdf转word3.0
- 二叉树
- 互斥锁与读写锁使用
- 删除链表中的中间节点和 a/b 处的结点 Python 版
- java面试(2)
- 给定一个百分制的分数,输出相应的等级。 90分以上 A级 80~89 B级 70~79 C级
- 使用ArrayList集合,对其添加100个不同的元素: 1.使用add()方法将元素添加到ArrayList集合对象中; 2.调用集合的iterator()方法获得Iterator对象,并调用Ite
- 揭秘京东文件系统JFS的前世今生,支持双11每秒约10万个对象同时读写
- Mac “'geckodriver' executable needs to be in PATH”
- Windows上安装ArcGIS Portal10.5以 Windows Server 2012 R2上安装ArcGIS Enterprise10.5
- Leetcode 算法设计 第十三周