以下是整理出的5个典型golang死锁场景:

1、主线程在通道写入之前,先行读取

    func main() {

        ch := make(chan int[, n])

        fmt.Println(<-ch)

        go func() {

            ch <- 1

        }()

    }

    func main() {

        ch := make(chan int[, n])

            fmt.Println(<-ch)

            ch <- 1

    }

2、主线程对无缓冲通道(或缓冲已满),先行写入

    func main() {

        ch := make(chan int)

        ch <- 1

        go func() {

            fmt.Println(<-ch)

        }()

    }

    func main() {

        ch := make(chan int)

        ch <- 1

        fmt.Println(<-ch)

    }

3、主线程内,读取通道次数超过协程中写入次数

    func main() {

        ch := make(chan int[, n])

        go func() {

            ch <- 1

        }()

        //多次读取

        fmt.Println(<-ch, <-ch)

        //或轮询监听

        for v := range ch {

            fmt.Println(v)

        }

    }

4、主线程内,对多个通道挨个读取的顺序,与协程中写入的不一致(除非通道有足够的缓冲)

—— 协程中写入下一个通道时,因上一个通道堵塞而被锁,造成主线程读取一个空通道而死锁

    func main() {

        ch1 := make(chan int)

        ch2 := make(chan int)

        go func() {

            ch1 <- 1

            ch2 <- 2

        }()

        fmt.Println(<-ch2)     //这里读取的顺序颠倒

        fmt.Println(<-ch1)

    }

5、通道1中调用了通道2,通道2中调用通道1

—— 2个通道相互调用,监听读取的永远都是空通道,造成主线程死锁等待

    func main() {

        ch1 := make(chan int)

        ch2 := make(chan int)

        go func() {

            select {

            case <-ch1:

                ch2 <- 20

            }

        }() 

        select {

        case <-ch2:

            ch1 <- 10

        }

    }

总结:

1、golang死锁全部发生在主线程

2、死锁的原因无外乎以下2种情况:

—— 主线程读取一个空的,且没有被close的通道

—— 通道缓冲不足时,主线程向没有协程消费的通道写入