go并发编程系列四:线程分组及控制线程的执行

发布时间 2023-09-02 16:13:17作者: jamstack

背景:在上一篇中,作为班主任的你,对班级的管理初见成效,但理想和现实总有差距,理想情况下,从接手一个调皮的班级到班级的管理井井有条,然而,现实是:班级里少不了调皮的学生,对于这样的情况,应该怎么办呢?本文仅以讲解技术为出发点,不代表教育观点。

有一个万不得已的办法是:听话的学生和调皮的学生互不干扰。

对应为线程,就是对线程进行分组,按组执行。

在我们的假定场景中,张三、李四是听话的学生,自然是一组,王五是一组,三个学生需要完成一组任务,同时我们希望同一组的张三、李四共同完成任务。

我们把上述业务场景拆分为技术片段:张三、李四分组 + 张三、李四共同完成任务+王五单独一组+王五肚子完成自己的任务

分组的概念很好理解,那么:张三、李四共同完成任务意味着什么呢?直白的说,就是张三、王五对应的线程不再各自持有互斥锁,变为普通线程,以便可以交替执行。

为了进一步演示这个场景,我们引入了任务的工具类:init.go,代码如下:

package concurrent

var task = map[int]string{1:"起床", 2:"洗漱", 3:"吃饭"} // 班主任规定的一组任务

 

模拟班级的代码如下:

package concurrent

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

// 在这个例子里,我们希望王五不要捣乱,等张三和李四竞争完,王五再出现
// 即:张三和李四先竞争,王五最后独自行动

var mutexImprove sync.Mutex // 创建一个互斥锁

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()

此时,执行代码,可以看到张三、李四是一组的,并且是交替执行,王五是独立的,这也就意味着我们完成了班级的管理目标。