一、前言

Go语言的内存模型规定了一个goroutine可以看到另外一个goroutine修改同一个变量的值的条件,这类似java内存模型中内存可见性问题(Java内存可见性问题可以参考拙作:Java并发编程之美一书)。

当多个goroutine并发同时存取同一个数据时候必须把并发的存取的操作顺序化,在go中可以实现操作顺序化的工具有高级的通道(channel)通信和同步原语比如sync包中的Mutex(互斥锁)、RWMutex(读写锁)或者和sync/atomic中的原子操作。

二、Happens Before原则

当程序里面只有一个goroutine时候,虽然编译器和CPU由于开启了优化功能可能调整读写操作的顺序,但是这个调整是不会影响程序的执行正确性:

a := 1//1
b := 2//2
c := a + b //3
...

如上代码由于编译器和cpu的优化,实际运行时候可能代码(2)先运行,然后代码(1)后执行,但是由于代码(3)依赖代码(1)和代码(2)创建的变量,所以代码(1)和(2)不会被放到代码(3)后运行,也就是说编译器和CPU在不改变程序正确性的前提下才会对指令进行重排序,所以上面代码在单一goroutine时候并不会存在问题,也就是在单一goroutine 中Happens Before所要表达的顺序就是程序执行的顺序。

但是在多个goroutine时候就可能存在问题,