go并发编程系列四:线程分组及控制线程的交替执行
背景:在上一篇中,作为班主任的你,对班级的管理初见成效,但理想和现实总有差距,理想情况下,从接手一个调皮的班级到班级的管理井井有条,是从0到1的跨越,没有中间的过渡阶段,然而,现实是:班级里少不了调皮的学生,对于这样的情况,应该怎么办呢?这篇文章讲解的正是现实中从0到1的过渡阶段,本文仅以讲解技术为出发点,不代表教育观点。
有一个万不得已的办法是:听话的学生和调皮的学生互不干扰。
对应为线程,就是对线程进行分组,按组执行。
在我们的假定场景中,张三、李四是听话的学生,自然是一组,王五是一组,三个学生需要完成一组任务,同时我们希望同一组的张三、李四交替完成任务。
我们把上述业务场景拆分为技术片段:张三、李四分组 + 张三、李四交替完成任务 + 王五单独一组 + 王五独自完成自己的任务
分组的概念很好理解,那么:张三、李四交替完成任务意味着什么呢?直白的说,就是张三、王五对应的线程不再各自持有互斥锁,变为普通线程,以便可以交替执行。
这里多说一点,线程的执行可以分为三个层级:1、交替执行 => 2、按序执行(竞争执行)=> 3、合作执行,这篇文章里,我们讲的是第一个层级,即:交替执行。
为了进一步演示这个场景,我们引入了任务的工具类:init.go,代码如下:
package concurrent var task = map[int]string{1:"起床", 2:"洗漱", 3:"吃饭"} // 班主任规定的一组任务
模拟班级的代码如下:
package concurrent import ( "fmt" "sync" "time" ) // 在这个例子里,我们希望王五不要捣乱,等张三和李四交替完成任务,王五再出现 // 即:张三和李四对应的线程先执行,王五对应的线程最后执行 func ThreadMutexImporveZhangSan(wg *sync.WaitGroup) { defer wg.Done() for i :=1; i <= 3; i++ { fmt.Println("张三:", task[i]) time.Sleep(time.Millisecond * 500) } } func ThreadMutexImproveLiSi(wg *sync.WaitGroup) { defer wg.Done() for i := 1; i <= 3; i++ { fmt.Println("李四:", task[i]) time.Sleep(time.Millisecond * 500) } } func ThreadMutexImproveWangWu() { for i := 1; i <= 3; i++ { fmt.Println("王五*:", task[i]) time.Sleep(time.Millisecond * 500) } }
为了适应线程分组,main.go的代码需要引入sync.WaitGroup,代码如下:
wgImprove.Add(2) go concurrent.ThreadMutexImporveZhangSan(&wgImprove) go concurrent.ThreadMutexImproveLiSi(&wgImprove) wgImprove.Wait() go concurrent.ThreadMutexImproveWangWu()
此时,执行代码,可以看到张三、李四是一组的,并且是交替执行,王五是独立的,这也就意味着我们完成了班级的管理目标。
在下一篇文章中,我们将讲解第二个层级:按序执行。