Go中指针、channel和并发需谨慎设计:T是RPC推荐的reply类型,T易出错,值类型无法回写;chan T适用于可变大结构体但需防悬空指针;for range闭包要传参避免共享变量;mutex应只锁共享字段,避免与channel阻塞互锁。

Go 里指针不是“拿来就用”的工具,而是需要和值拷贝、通道语义、RPC 协议层层对齐的机制;并发也不是“开 goroutine 就完事”,稍不注意就会卡死在 channel 上或读到陈旧数据。
Go RPC 中 *T 和 **T 的实际区别:别让 reply 变成空壳
Java 开发者习惯把对象传进方法让它被修改,但在 Go 的 rpc.Call 中,reply 参数是“输出槽位”,它的类型直接决定你能不能拿到更新后的数据:
- 用
*Task作 reply 类型:RPC 框架会把返回值 copy 到你传入的指针指向的内存 —— 安全、直观、推荐 - 用
**Task:你需要先 new 出一个*Task,再取地址传进去,调用后还要解两次引用,极易漏判 nil,且 Go 标准 RPC 对双指针支持不稳定 - 用
Task(值类型):框架只 copy 值,Worker 修改task.TaskId后,Coordinator 里原结构体完全不受影响
典型错误现象:Worker 调用 GetTask 后成功拿到任务,但后续调用 ReportTask 时发现 TaskId 是 0 —— 因为 reply 是值类型,修改没回写。
channel 存值还是存指针?看你的数据是否可变
Java 里 Queue<task></task> 天然共享引用,Go 的 chan Task 却每次收发都拷贝整个结构体。一旦结构体含 slice、map 或大字段,性能和一致性都会出问题:
立即学习“Java免费学习笔记(深入)”;
- 结构体小、只读、无指针字段(如
type ID struct{ N int })→ 用chan ID完全 OK - 结构体含
[]byte、map[string]string,或 Worker 需要就地更新状态(如task.Status = "done")→ 必须用chan *Task - 改用指针通道后,必须确保没有 goroutine 在修改同一实例的同时,另一个 goroutine 正从通道中取出它 —— 这时候得加
sync.Mutex或改用不可变设计
常见错误:Coordinator 把 &task 发进 chan *Task,但 task 是栈上局部变量,发送完函数退出,指针立刻悬空 —— Worker 收到的就是野指针,运行时 panic。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
for range + goroutine 的闭包陷阱:p 不是你要的那个 p
Java 8+ 的 lambda 会捕获 final 变量的值,Go 的匿名函数却捕获的是变量本身。下面这段代码在 Java 里输出 1 和 2,在 Go 里大概率输出两个 2:
<pre class="brush:php;toolbar:false;">for _, p := range persons {
go func() {
fmt.Println(p.ID) // p 是循环变量,所有 goroutine 共享同一个地址
}()
}
正确写法只有两种:
- 显式传参:
go func(p Person) { fmt.Println(p.ID) }(p) - 用索引访问:
go func(i int) { fmt.Println(persons[i].ID) }(i)
别依赖 time.Sleep 来“修复”——那只是掩盖了竞态,上线压测时照样崩。
sync.Mutex 不是万能锁:别在 channel 操作前后机械加锁
Java 开发者容易把 synchronized 当成安全符,但在 Go 里,锁的粒度错一点,就会和 channel 阻塞互相卡死:
- 错误模式:在
select前加锁,然后阻塞在<-ch上 → 其他 goroutine 拿不到锁,也进不了这个 select,死锁 - 正确做法:只锁真正共享的字段读写,比如
task.Status;channel 收发本身是线程安全的,不需要额外锁 - 更推荐方案:用
sync/atomic替代锁操作简单字段(如int32计数器),或直接用 channel 做状态同步(比如用done chan struct{}代替mu.Lock())
最容易被忽略的一点:Go 的 mutex 不提供内存屏障语义,如果只靠锁保护一个字段,但其他字段没被锁覆盖,仍可能出现部分写入可见的问题 —— 这时候得搭配 atomic.StorePointer 或彻底转向 channel 驱动模型。

















