golang 会自动加锁保证并发安全吗?

golang 的版本是 1.9.2

最近接触 golang 的并发加锁功能,按照例子做了一个多 goroutine 计数的练习,发现加锁和不加锁的运行结果是一样的,请问这是机器的缘故吗?(至少在我的电脑上和 https://play.golang.org/ 上模拟是这样的) 还是说 1.9 版本的 go 已经不用 mutex 锁数据了?如果是我的测试方法的问题,那么如何能正确的方式测试出加锁和不加锁的区别呢?

代码如下:

package main

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

type SafeCounter struct {
    v  map[string]int
    mux sync.Mutex
}

func (c *SafeCounter) Inc(key string) {

    c.mux.Lock()

    c.v[key]++

    c.mux.Unlock()
}

func (c *SafeCounter) Value(key string) int {

    defer c.mux.Unlock()

    c.mux.Lock()

    return c.v[key]
}

func main() {
    c := SafeCounter{
        v: make(map[string]int),
    }

    for i := 0; i < 1000; i++ {
        go c.Inc("somekey")
    }

    time.Sleep(time.Second)

    fmt.Println(c.Value("somekey"))
}

输出结果是 1000
把所有的锁去掉,还是 1000

阅读 7.8k
4 个回答
  • 原生的map是非线程安全的。从go1.6开始,runtime会对并发读写map进行检测,一旦检测到有并发读写map的情况,会引发crash。
  • sync.Map是线程安全的。

不要抱有侥幸心理,map不加锁肯定会崩的,到了线上直接是程序异常退出,你的例子没有问题,可能多跑几趟才会出现panic,你尝试使用go run -race main.go,检查下有没有数据竞争。

不会,并且go不保证所有的goroutine是同步执行的,并且还会对语句进行重新排序(一个goroutine监测到的执行顺序可能与另一个goroutine监测到的不同)

使用sync和sync/atomic包保证线程同步与线程安全

http://docscn.studygolang.com...
https://golang.org/ref/mem

很明显不会,虽然用golang的地方大多都会涉及到并发安全处理,所以我在项目中封装了很多并发安全的包以及类型:http://gf.johng.cn/494392

顺便提一下,golang的atomic原子操作是所有锁机制中效率最高的,能够使用原子操作的地方,就尽量用原子操作吧。我实现的并发安全基本类型gtype包底层大多数也是基于atomic。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题