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

###互斥锁golang

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

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)
}

###读写锁并发

读写锁便是针对于读写操做的互斥锁。它与普通的互斥锁最大的不一样就是,它能够分别针对读操做和写操做进行锁定和解锁操做。读写锁遵循的访问控制规则与互斥锁有所不一样。this

在读写锁管辖的范围内,它容许任意个读操做的同时进行。可是,在同一时刻,它只容许有一个写操做在进行。而且,在某一个写操做被进行的过程当中,读操做的进行也是不被容许的。.net

也就是说,读写锁控制下的多个写操做之间都是互斥的,而且写操做与读操做之间也都是互斥的。可是,多个读操做之间却不存在互斥关系。线程

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)
}

读写锁小例子

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

参考

GO语言并发编程之互斥锁、读写锁详解code

golang中sync.RWMutex和sync.Mutex区别htm

相关文章
相关标签/搜索