Go 并发基础:goroutine 与 channel(面向 Java 开发者)

2026-01-19 09:08:07 3阅读

如果你是 Java 后端,第一次接触 Go 并发,大概率会有一个感觉:

“怎么这么简单?是不是哪里藏了坑?”

这篇文章我们就用 Java → Go 的对照视角,把 Go 并发里最核心的两个概念讲清楚:

一、先抛结论:Go 并发和 Java 并发“思路完全不同”Java 并发的核心是:

一句话总结:

Java:多个线程抢同一块内存,用锁保证安全

Go 并发的核心是:

一句话总结:

Go:不共享内存,通过通信来传递数据

这不是语法差异,而是并发哲学的差异。

二、goroutine:比 Java Thread 轻太多了1️⃣ Java 创建一个线程

new Thread(() -> {
    System.out.println("hello");
}).start();

问题你一定很熟:

2️⃣ Go 创建一个 goroutine

go func() {
    fmt.Println("hello")
}()

只有一个 go 关键字。

3️⃣ goroutine 到底轻在哪里?

所以在 Go 里:

for i := 0; i < 100000; i++ {
    go work(i)
}

这是完全正常的写法。

三、channel:Go 并发的灵魂

如果说 goroutine 是“人”,

那 channel 就是 goroutine 之间说话的方式。

1️⃣ 一个最简单的 channel 示例

ch := make(chan int)
go func() {
    ch <- 10 // 发送
}()
v := <-ch   // 接收
fmt.Println(v)

你可以把 channel 理解成:

一个类型安全、可阻塞的队列

2️⃣ channel = 数据通道 + 同步工具

这一点对 Java 程序员非常重要:

ch <- data

这行代码可能会阻塞,直到:

️ Go 把“同步”内置进了通信模型

3️⃣ Java 视角下的类比

但要注意:

channel 不只是队列,更是并发设计工具

四、无缓冲 vs 有缓冲 channel1️⃣ 无缓冲 channel(默认)

ch := make(chan int)

特点:

done := make(chan struct{})
go func() {
    doWork()
    done <- struct{}{}
}()
<-done // 等待完成

2️⃣ 有缓冲 channel

ch := make(chan int, 3)

特点:

五、一个典型并发模式:fan-out / fan-in多 goroutine 并发处理任务

jobs := make(chan int)
results := make(chan int)
for i := 0; i < 5; i++ {
    go worker(jobs, results)
}
for j := 0; j < 10; j++ {
    jobs <- j
}
close(jobs)
for i := 0; i < 10; i++ {
    <-results
}

你会发现:

但并发逻辑非常清晰

六、那 Go 还要不要锁?

要,但不是第一选择。

Go 的推荐顺序是:

优先用 channel实在不合适,再用 sync.Mutex不要一上来就锁

这也是 Go 官方名言:

Don’t communicate by sharing memory; share memory by communicating.

七、给 Java 程序员的几个“避坑提醒”️ 1. main goroutine 结束,程序直接退出

go doWork()

如果 main 函数结束了,goroutine 不会等你。

️ 用 WaitGroup 或 channel 控制生命周期。

️ 2. 不要随意 close channel️ 3. 并发不是越多越好

goroutine 很轻,但:

依然是瓶颈。

八、总结一句话

Go 用 goroutine 降低并发成本,用 channel 降低并发复杂度。

如果你是 Java 开发者,转 Go 最大的转变不是语法,而是:

从“锁思维”切换到“通信思维”

免责声明:由于无法甄别是否为投稿用户创作以及文章的准确性,本站尊重并保护知识产权,根据《信息网络传播权保护条例》,如我们转载的作品侵犯了您的权利,请您通知我们,请将本侵权页面网址发送邮件到qingge@88.com,深感抱歉,我们会做删除处理。