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

相關文章
相關標籤/搜索