go 安全map 实现, 互斥锁和读写锁

2019-07-22 16:51:44 浏览数 (2)

互斥锁

其中Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁叶叫做全局锁.

代码语言:javascript复制
package main

import (
	"fmt"
	"sync"
	"errors"
)

type MyMap struct {
	mp map[string]int
	mutex *sync.Mutex
}

func (this *MyMap) Get(key string) (int, error)  {
	this.mutex.Lock()
	i, ok := this.mp[key]
	this.mutex.Unlock()
	if !ok {
		return i, errors.New("不存在")
	}
	return i, nil
}

func (this *MyMap) Set(key string, v int)  {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	this.mp[key] =  v
}

func (this *MyMap) Display()  {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	for k,v := range this.mp  {
		fmt.Println(k, "=", v)
	}
}

func SetValue(m *MyMap) {
	var a rune
	a = 'a'
	for i:=0; i<10; i    {
		m.Set(string(a rune(i)),i)
	}
}


func main() {
	m := &MyMap{mp:make(map[string]int), mutex:new(sync.Mutex)}
	go SetValue(m) /*启动一个线程向 map 写入值*/
	go m.Display() /*启动一个线程读取 map 的值*/
	var str string /*这里主要是等待线程结束*/
	fmt.Scan(&str)
}

读写锁

读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。读写锁遵循的访问控制规则与互斥锁有所不同。

在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。并且,在某一个写操作被进行的过程中,读操作的进行也是不被允许的。

也就是说,读写锁控制下的多个写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的。但是,多个读操作之间却不存在互斥关系。

代码语言:javascript复制
package main

import (
	"fmt"
	"sync"
	"errors"
)

type MyMap struct {
	mp map[string]int
	mutex *sync.RWMutex
}

func (this *MyMap) Get(key string) (int, error)  {
	this.mutex.RLock()
	i, ok := this.mp[key]
	this.mutex.RUnlock()
	if !ok {
		return i, errors.New("不存在")
	}
	return i, nil
}

func (this *MyMap) Set(key string, v int)  {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	this.mp[key] =  v
}

func (this *MyMap) Display()  {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	for k,v := range this.mp  {
		fmt.Println(k, "=", v)
	}
}

func SetValue(m *MyMap) {
	var a rune
	a = 'a'
	for i:=0; i<10; i    {
		m.Set(string(a rune(i)),i)
	}
}


func main() {
	m := &MyMap{mp:make(map[string]int), mutex:new(sync.RWMutex)}
	go SetValue(m) /*启动一个线程向 map 写入值*/
	go m.Display() /*启动一个线程读取 map 的值*/
	var str string /*这里主要是等待线程结束*/
	fmt.Scan(&str)
}
读写锁小例子
代码语言:javascript复制
package main

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

func main() {
	var lock sync.RWMutex
	go read(&lock)
	go read(&lock)
	go write(&lock)
	time.Sleep(25000000)
	fmt.Println("end")
}

func read(lock *sync.RWMutex) {
	lock.RLock()
	fmt.Println("reading")
	time.Sleep(5000)
	fmt.Println("read end")
	lock.RUnlock()
}

func write(lock *sync.RWMutex) {
	time.Sleep(1000)//保证先让读拿到锁, 如果没有就会随机,不过应该先过read一般会先read.
	lock.Lock()
	fmt.Println("writing")
	time.Sleep(5000)
	fmt.Println("write end")
	lock.Unlock()
}


//结果
reading
reading
read end
read end
writing
write end
end

0 人点赞