什么是Java synchronized()块的golang等价物?

Bra*_*ody 14 synchronization go

Java为同步代码的关键部分提供了一个非常方便的习惯用法:

synchronized(someObject) {
    // do something really important all by myself with nobody bothering me
}
Run Code Online (Sandbox Code Playgroud)

要么

public synchronized void doSomething() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

什么是等效的?

(快速搜索显示:golang.org/pkg/sync/ - 看起来(可能是我错了)对于一般用途来说有点太低了.)

(我关心的原因示例:我需要通过通道向多个侦听器发送消息.通道为数据提供了良好的管道而无需同步任何内容,但是当添加或删除通道时,我需要修改通道列表,可能在任何时候发生必须能够处理并发.)

tar*_*lah 15

sync.Mutex是一个互斥锁,它可以提供与synchronizedjava关键字类似的功能(除了java中的锁提供reentrant互斥):

synchronized(someObject) {
    //   
}
Run Code Online (Sandbox Code Playgroud)

相当于:

var l sync.Mutex

l.Lock()
//
l.Unlock()
Run Code Online (Sandbox Code Playgroud)

  • http://play.golang.org/p/jfeBxkve65可以在Java中运行,但在Go中会出现死锁.继承不起作用. (5认同)

Pau*_*kin 9

使用互斥锁的另一种解决方案是使用通道来传达侦听器更改.

这种风格的完整示例如下所示.有趣的代码在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)
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 9

延伸tarrsalah的答案.

您可以将sync.Mutex添加到您的对象,允许它们直接锁定和解锁.

type MyObject struct{
    Number int
    sync.Mutex
}

func (m *MyObject)Increment(){
    m.Lock()
    defer m.Unlock()
    m.Number++
}
Run Code Online (Sandbox Code Playgroud)

Defer'd命令将在函数结束时运行,这样你知道它在更大的函数中被锁定和解锁.

  • 这个答案更好,因为它提到推迟.手动调用unlock()很容易出现死锁 (2认同)