Golang中与Java的synchronized()块等效的是什么?

huangapple go评论69阅读模式
英文:

what is the golang equivalent of a Java synchronized() block?

问题

Java提供了一种非常方便的习语来同步代码的关键部分:

synchronized(someObject) {
    // 独自完成一些非常重要的事情,没有人打扰我
}

或者

public synchronized void doSomething() {
    // ...
}

Go语言的等效方式是什么?

(快速搜索结果显示:<a href="http://golang.org/pkg/sync/">golang.org/pkg/sync/</a> - 这似乎(也许我错了)对于一般用途来说有点太底层。)

(为什么我关心这个的例子:我需要通过通道向多个监听器发送消息。通道为数据提供了一个良好的传输通道,而无需同步任何内容,但是当通道被添加或删除时,我需要修改通道列表,这可能随时发生,必须能够处理并发。)

英文:

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: <a href="http://golang.org/pkg/sync/">golang.org/pkg/sync/</a> - 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

得分: 22

sync.Mutex 是一种互斥锁,它可以提供类似于 Java 中的 synchronized 关键字的功能(除了 Java 中的锁提供了可重入的互斥)。

synchronized(someObject) {
    // 
}

等价于:

var l sync.Mutex

l.Lock()
//
l.Unlock()
英文:

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

得分: 16

扩展tarrsalah的答案。

您可以将sync.Mutex添加到您的对象中,以便可以直接对其进行锁定和解锁。

type MyObject struct{
    Number int
    sync.Mutex
}

func (m *MyObject)Increment(){
    m.Lock()
    defer m.Unlock()
    m.Number++
}

延迟的命令将在函数末尾运行,这样您就知道它既被锁定又被解锁,在更大的函数中也适用。

英文:

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

得分: 9

使用互斥锁的另一种解决方案是使用通道来进行监听器的通信。

以下是一个完整的示例,代码的重点在于FanOuter函数。

package main

import (
	"fmt"
	"time"
)

type Message int

type ListenerUpdate struct {
	Add      bool
	Listener chan Message
}

// FanOuter维护监听器,并将来自msgc的消息转发给每个监听器。listc上的更新可以添加或删除监听器。
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)
	// 慢慢添加监听器,然后慢慢删除它们。
	go func() {
		chans := make([]chan Message, 10)
		// 添加监听器。
		for i := range chans {
			chans[i] = make(chan Message)
			// 监听器打印其ID和接收到的任何消息。
			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)
		}
		// 删除监听器。
		for i := range chans {
			listc <- ListenerUpdate{false, chans[i]}
			time.Sleep(300 * time.Millisecond)
		}
	}()
	// 每秒向fanouter发送一条消息。
	for i := 0; i < 10; i++ {
		fmt.Println("About to send ", i)
		msgc <- Message(i)
		time.Sleep(1 * time.Second)
	}
}

希望对你有帮助!

英文:

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 (
&quot;fmt&quot;
&quot;time&quot;
)
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 := &lt;-msgc:
for k := range lstrs {
k &lt;- m
}
case lup := &lt;-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 := &lt;-c
fmt.Printf(&quot;%d received %d\n&quot;, i, m)
}
}(i, chans[i])
listc &lt;- ListenerUpdate{true, chans[i]}
time.Sleep(300 * time.Millisecond)
}
// Removing listeners.
for i := range chans {
listc &lt;- ListenerUpdate{false, chans[i]}
time.Sleep(300 * time.Millisecond)
}
}()
// Every second send a message to the fanouter.
for i := 0; i &lt; 10; i++ {
fmt.Println(&quot;About to send &quot;, i)
msgc &lt;- Message(i)
time.Sleep(1 * time.Second)
}
}

huangapple
  • 本文由 发表于 2013年9月19日 03:20:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/18880575.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定