1. 前提

Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。

2. map并发读写测试

package main

import (
	"os/signal"
	"runtime"
	"syscall"
)

func main()  {
	// 创建一个int到int的映射
	m := make(map[int]int)
	// 开启一段并发代码
	go func() {
		// 不停地对map进行写入
		for {
			m[1] = 1
		}
	}()
	// 开启一段并发代码
	go func() {
		// 不停地对map进行读取
		for {
			_ = m[1]
		}
	}()

	signal.Ignore(syscall.SIGHUP)
	runtime.Goexit()
}

运行时报错
fatal error: concurrent map read and map write

3. 接下来用并发安全的sync.Map来测试

package main

import (
	"fmt"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
)

func main()  {
	// 创建一个int到int的映射
	m := sync.Map{}
	// 开启一段并发代码
	go func() {
		// 不停地对map进行写入
		for {
			m.Store(1,1)
		}
	}()
	// 开启一段并发代码
	go func() {
		// 不停地对map进行读取
		for {
			if v, ok := m.Load(1); ok{
				fmt.Println(v)
			}
		}
	}()

	signal.Ignore(syscall.SIGHUP)
	runtime.Goexit()
}

运行时会一直输出1而不会报错

4. sync.Map基本操作

4.1 创建

直接声明,不需要make
var m sync.Map

4.2 插入、修改

  • 如果key不存在,插入value;
  • 如果key存在则修改其值
m.Store(key,value)

4.3 插入或查找

  • 如果key不存在,插入value,返回插入value的值,ok为false
  • 如果key存在,返回原map中value的值,ok为true
value,ok := m.LoadOrStore(key,value)

4.4 删除

m.Delete(key)

4.5 查找

v,ok := m.Load(key)

4.6 遍历

m.Range(func(k, v interface{}) bool {
  fmt.Println("interate:",k,v)
  return true
})