问题
Java provides a very convenient idiom for synchronizing critical portions of code:
synchronized(someObject) {
// do something really important all by myself with nobody bothering me
}
Or
public synchronized void doSomething() {
// ...
}
What is the go equivalent?
(A quick search reveals: golang.org/pkg/sync/ - which seems (maybe I'm wrong) a bit too low level for general use.)
(Example of why I care about this: I need to send a message to multiple listeners via channels. Channels provide a good conduit for the data without having to synchronize anything, but when channels are added or removed I need to modify the list of channels, which might happen at any time must be able to deal with concurrency.)
回答1:
sync.Mutex is a mutual exclusion lock, it can provide a similar functionality to the synchronized
java key-word (except that locks in java provide reentrant
mutual exclusion) :
synchronized(someObject) {
//
}
Is equivalent to :
var l sync.Mutex
l.Lock()
//
l.Unlock()
回答2:
to extend off tarrsalah's answer.
You can add sync.Mutex to your object, allowing them to be directly locked and unlocked.
type MyObject struct{
Number int
sync.Mutex
}
func (m *MyObject)Increment(){
m.Lock()
defer m.Unlock()
m.Number++
}
Defer'd commands will run at the end of the function, this way you know it gets both locked and unlocked, in bigger functions.
回答3:
A different solution to using a mutex is to use a channel to communicate listener changes.
A full example in this style looks like this. The interesting code is in 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)
}
}
来源:https://stackoverflow.com/questions/18880575/what-is-the-golang-equivalent-of-a-java-synchronized-block