java 使用 BlockingQueue 时是否需要额外的同步?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3661282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:54:33  来源:igfitidea点击:

Do I need extra synchronization when using a BlockingQueue?

javamultithreadingsynchronization

提问by David Hofmann

I have a simple bean @Entity Message.java that has some normal properties. The life-cycle of that object is as follows

我有一个简单的 bean @Entity Message.java,它有一些正常的属性。该对象的生命周期如下

Instantiation of Message happens on Thread A, which is then enqueued into a blockingQueue

Message 的实例化发生在线程 A 上,然后将其排入阻塞队列

Another thread from a pool obtains that object and do some stuff with it and changes the state of Message, after that, the object enters again into the blockingQueue. This step is repeated until a condition makes it stop. Each time the object gets read/write is potentially from a different thread, but with the guarantee that only one thread at a time will be reading/writing to it.

池中的另一个线程获取该对象并对其执行一些操作并更改 Message 的状态,然后该对象再次进入阻塞队列。重复此步骤,直到出现条件使其停止。每次对象获得读/写都可能来自不同的线程,但保证一次只有一个线程会读/写它。

Given that circumstances, do I need to synchronize the getters/setters ? Perhaps make the properties volatile ? or can I just leave without synchronization ?

鉴于这种情况,我是否需要同步 getter/setter ?也许使属性不稳定?或者我可以不同步就离开吗?

Thanks and hope I could clarify what I am having here.

谢谢并希望我能澄清我在这里的情况。

回答by erickson

No, you do not need to synchronize access to the object properties, or even use volatileon the member variables.

不,您不需要同步访问对象属性,甚至不需要volatile在成员变量上使用。

All actions performed by a thread before it queues an object on a BlockingQueue"happen-before" the object is dequeued. That means that any changes made by the first thread are visible to the second. This is common behavior for concurrent collections. See the last paragraph of the BlockingQueueclass documentation:

线程在将对象排队之前执行的所有操作都BlockingQueue在对象出列前“发生”。这意味着第一个线程所做的任何更改对第二个线程都是可见的。这是并发集合的常见行为。请参阅BlockingQueue类文档的最后一段:

Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a BlockingQueuehappen-beforeactions subsequent to the access or removal of that element from the BlockingQueuein another thread.

内存一致性影响:与其他并发集合一样,线程中的操作在将对象放入BlockingQueue之前发生的操作之前BlockingQueue在另一个线程中访问或删除该元素之后。

As long as the first thread doesn't make any modifications after queueing the object, it will be safe.

只要第一个线程在对象排队后不做任何修改,就是安全的。

回答by irreputable

You don't need to do synchronization yourself, because the queue does it for you already.

您不需要自己进行同步,因为队列已经为您完成了。

Visibility is also guaranteed.

能见度也得到保证。

回答by Vivien Barousse

If you're sure that only one thread at a time will access your object, then you don't need synchronisation.

如果您确定一次只有一个线程会访问您的对象,那么您就不需要同步。

However, you can ensure that by using the synchronized keyword: each time you want to access this object and be sure that no other thread is using the same instance, wrap you code in a synchronized block:

但是,您可以通过使用 synchronized 关键字来确保:每次您想要访问此对象并确保没有其他线程正在使用相同的实例时,将您的代码包装在一个同步块中:

Message myMessage = // ...
synchronized (myMessage) {
    // You're the only one to have access to this instance, do what you want
}

The synchronized block will acquire an implicit lock on the myMessage object. So, no other synchronized block will have access to the same instance until you leave this block.

同步块将获得对 myMessage 对象的隐式锁定。因此,在您离开此块之前,没有其他同步块可以访问同一个实例。

回答by tylermac

It would sound like you could leave of the synchronized off the methods. The synchronized simply locks the object to allow only a single thread to access it. You've already handled that with the blocking queue.

听起来您可以离开同步方法。synchronized 只是简单地锁定对象,只允许一个线程访问它。您已经使用阻塞队列处理过这个问题。

Volatile would be good to use, as that would ensure that each thread has the latest version, instead of a thread local cache value.

使用易失性会很好,因为这将确保每个线程都具有最新版本,而不是线程本地缓存值。