Java为同步代码的关键部分提供了非常方便的习惯用法:
synchronized(someObject) {
// do something really important all by myself with nobody bothering me
}
或者
public synchronized void doSomething() {
// ...
}
什么是等效的?
(快速搜索显示:golang.org/pkg/sync/ - 看起来(可能我错了)通常使用的程度太低了。)
(我关心的原因示例:我需要通过通道向多个侦听器发送消息。通道为数据提供了良好的管道而无需同步任何内容,但是当添加或删除通道时,我需要修改可能在任何时候发生的频道列表必须能够处理并发。)
答案 0 :(得分:12)
sync.Mutex是一个互斥锁,它可以提供与synchronized
java关键字类似的功能(除了java中的锁提供reentrant
互斥):
synchronized(someObject) {
//
}
相当于:
var l sync.Mutex
l.Lock()
//
l.Unlock()
答案 1 :(得分:8)
使用互斥锁的另一种解决方案是使用通道来传达侦听器更改。
此样式的完整示例如下所示。有趣的代码在FanOuter。
package main
import (
"fmt"
"time"
)
type Message int
type ListenerUpdate struct {
Add bool
Listener chan Message
}
// FanOuter maintains listeners, and forwards messages from msgc
// to each of them. Updates on listc can add or remove a listener.
func FanOuter(msgc chan Message, listc chan ListenerUpdate) {
lstrs := map[chan Message]struct{}{}
for {
select {
case m := <-msgc:
for k := range lstrs {
k <- m
}
case lup := <-listc:
if lup.Add {
lstrs[lup.Listener] = struct{}{}
} else {
delete(lstrs, lup.Listener)
}
}
}
}
func main() {
msgc := make(chan Message)
listc := make(chan ListenerUpdate)
go FanOuter(msgc, listc)
// Slowly add listeners, then slowly remove them.
go func() {
chans := make([]chan Message, 10)
// Adding listeners.
for i := range chans {
chans[i] = make(chan Message)
// A listener prints its id and any messages received.
go func(i int, c chan Message) {
for {
m := <-c
fmt.Printf("%d received %d\n", i, m)
}
}(i, chans[i])
listc <- ListenerUpdate{true, chans[i]}
time.Sleep(300 * time.Millisecond)
}
// Removing listeners.
for i := range chans {
listc <- ListenerUpdate{false, chans[i]}
time.Sleep(300 * time.Millisecond)
}
}()
// Every second send a message to the fanouter.
for i := 0; i < 10; i++ {
fmt.Println("About to send ", i)
msgc <- Message(i)
time.Sleep(1 * time.Second)
}
}
答案 2 :(得分:7)
延长了tarrsalah的答案。
您可以将sync.Mutex添加到您的对象,允许它们直接锁定和解锁。
type MyObject struct{
Number int
sync.Mutex
}
func (m *MyObject)Increment(){
m.Lock()
defer m.Unlock()
m.Number++
}
Defer'd命令将在函数结束时运行,这样你知道它在更大的函数中被锁定和解锁。