Go语言中通过Groutine 启动一个Go协程,不同协程之间是并发执行的,就像C++/Java中线程之间线程安全是一个常见的问题。
如下Go 语言代码:

func TestConcurrent(t *testing.T) {var counter int = 0for i := 0;i < 5000; i ++{go func() { // 启动groutine 进行变量的自增counter ++}()}time.Sleep(time.Second * 1)t.Logf("Counter = %d", counter)
}

最后的结果输出如下:

=== RUN   TestConcurrentconcurrent_test.go:18: Counter = 4663
--- PASS: TestConcurrent (1.00s)

希望变量Counter的结果是5000,最终因为协程之间并发访问共享内存的原因导致部分协程执行的结果没有得到变更,从而数据不符合预期。

Go中提供了MutexRWMutex ,来实现锁功能。前者就是正常的Lock, Unlock;后者提供了读写锁,在协程读写分离中提供了读读互不影响,读写互斥。

如下测试代码:

func TestMutex(t *testing.T) {var counter int = 0// var mu sync.Mutex // mutex lockvar mu sync.RWMutex // rwmutex lockfor i := 0;i < 5000; i ++{go func() {// defer mutex unlock// 如果协程异常退出,能够释放锁defer func() { mu.Unlock()}()mu.Lock()counter ++}()}time.Sleep(time.Second * 1)t.Logf("Counter = %d", counter)
}

最终输出如下,通过mutex 实现了变量访问的安全:

=== RUN   TestMutexconcurrent_test.go:36: Counter = 5000
--- PASS: TestMutex (1.01s)

可以看到如上代码需要通过Sleep来让所有的协程都执行完,显然不合理。、

假如有更多的协程,这个sleep时间还需要程序员来修改,Go语言提供了WaitGroup机制,就像是C++中的条件变量,主线程可以等待在条件变量上,当线程执行完可以通过条件变量唤醒主线程继续执行。
var wg sync.WaitGroup 声明一个WaitGroup变量
通过wg.Add(1)wg.Done() 来检测线程的完成情况,wg.Wait()表示主线程等待在wg变量上

func TestWaitGroup(t *testing.T) {var counter int = 0var mu sync.RWMutex // rw lock, 读写互斥var wg sync.WaitGroupfor i := 0;i < 5000; i ++{wg.Add(1) go func() {defer func() {mu.Unlock()}()mu.Lock()counter ++wg.Done() // wg.Add(-1)}()}wg.Wait()t.Logf("Counter = %d", counter)
}

输出如下,可以看到TestWaitGroup 函数的执行时间很快,不需要Sleep方式来消耗更多的时间使程序被动执行完毕。

=== RUN   TestWaitGroupconcurrent_test.go:57: Counter = 5000
--- PASS: TestWaitGroup (0.00s)

Go 分布式学习利器(18)-- Go并发编程之lock+WaitGroup实现线程安全相关推荐

  1. java线程安全的set_Java并发编程之set集合的线程安全类你知道吗

    Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥并发编程学习>系列之<并发集合系列& ...

  2. Java并发编程之Lock

    Java并发编程:Lock Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.uti ...

  3. java 时间戳_Java并发编程之CAS三CAS的缺点 及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  4. 并发编程之CPU缓存架构缓存一致性协议详解(二)

    并发编程之CPU缓存架构&缓存一致性协议详解 CPU高速缓存(Cache Memory) CPU高速缓存 在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就 ...

  5. Java 并发编程之美:并发编程高级篇之一-chat

    借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...

  6. Java 并发编程之美:并发编程高级篇之一

    借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...

  7. Java并发编程之CAS第三篇-CAS的缺点

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  8. cyclicbarrier java_Java并发编程之CyclicBarrier和线程池的使用

    原标题:Java并发编程之CyclicBarrier和线程池的使用 下面我们来讲述一下线程池和CyclicBarrier的使用和对比. 一.场景描述 有四个游戏玩爱好者玩游戏,游戏中有三个关卡,每一个 ...

  9. zbb20180929 thread java并发编程之Condition

    java并发编程之Condition 引言 在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object上监视器方法,包括wait(),wait(long timeout ...

最新文章

  1. 人工智能语音技术支持“多情感程度”调节,细腻演绎“人声”
  2. 一个 P4 的 Bug,就难倒了 JDK 吗 ?
  3. linux set include path,set_include_path()的用法
  4. Create and Manage Cases
  5. sunPKCS11加载动态库(转)
  6. 格雷码 matlab,基于格雷码的结构光重建代码(MATLAB版本)
  7. 关于韩京清学者的《直线型倒立摆的自抗扰控制设计方案》仿真
  8. jfinal中使用freemarker
  9. HTML学习笔记——DOCTYPE和DTD,标准模式和兼容模式
  10. 数据输出matlab,MATLAB数据输出
  11. github java 性能,JavaGuide/手把手教你定位常见Java性能问题.md at master · Github-Programer/JavaGuide · GitHub...
  12. JAVA生成随机昵称
  13. Redhat7/Centos7服务器设置IP地址
  14. 唐巧总结的40个国人iOS技术博客
  15. CAD输出为PDF至A4大小
  16. 【深度学习】详解 MAE
  17. 二次型如何快速转化为矩阵?
  18. jqgrid 动态设置单元格不可编辑
  19. oracle 小数格式化为百分数
  20. Kth Excluded

热门文章

  1. JVM自动内存管理:对象判定和回收算法
  2. java实体属性对应mysql和SQL Server 和Oracle 数据类型对应
  3. JavaScript高级程序设计(第3版)第六章读书笔记
  4. flex java socket通信
  5. 【目标检测】yolo系列:从yolov1到yolov5之YOLOv1详解及复现
  6. OpenCV+python:Canny边缘检测算法
  7. 多重集合的排列和组合问题
  8. php pthread安装编译,php 多线程扩展 pthreads 安装 及 使用
  9. php ajax 概率 转盘,php+jquery实现转盘抽奖 概率可任意调
  10. java ascii 编码方式_JAVA 的ASCII字符编码一览表