ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 互斥锁 惯例来说,被mutex所保护的变量是在mutex变量声明之后立刻声明的。如果你的做法和惯例不符,确保在文档里对你的做法进行说明。 ## 阻塞 调用mutex的Lock方法来获取一个互斥锁。如果其它的goroutine已经获得了这个锁的话,这个操作会被阻塞直到其它goroutine调用了Unlock使该锁变回可用状态。mutex会保护共享变量。 也就是说,当一个协程获得了锁之后,其它协程就会阻塞住,直到获取锁的协程unlock了. ## 临界区 在Lock和Unlock之间的代码段中的内容goroutine可以随便读取或者修改,这个代码段叫做临界区。 ## 互斥锁中使用defer 下面的例子里Unlock会在return语句读取完balance的值之后执行,所以Balance函数是并发安全的。这带来的另一点好处是,我们再也不需要一个本地变量b了。 **一个deferred Unlock即使在临界区发生panic时依然会执行**,这对于用recover来恢复的程序来说是很重要的。defer调用只会比显式地调用Unlock成本高那么一点点,不过却在很大程度上保证了代码的整洁性。大多数情况下对于并发程序来说,代码的整洁性比过度的优化更重要。如果可能的话尽量使用defer来将临界区扩展到函数的结束。 **这也就解释了,为什么defer被设计的在return之后才会执行,因为defer的操作,不想去影响正常的业务逻辑.** ~~~ func Balance() int { mu.Lock() defer mu.Unlock() return balance } ~~~ ## 死锁 对一个已经上锁的数据,再次上锁会造成死锁. 可以在看go语言圣经的这一段.蛮精彩的. ## 封装性 封装, 用限制一个程序中的意外交互的方式,可以使我们获得数据结构的不变性。因为某种原因,封装还帮我们获得了并发的不变性。当你使用mutex时,确保mutex和其保护的变量没有被导出(在go里也就是小写,且不要被大写字母开头的函数访问啦),无论这些变量是包级的变量还是一个struct的字段。 **上面的意思是,无论是被保护的数据,还是mutex锁本身,都不要能被变量直接访问到**.