[英]Java happens-before clarification and how to safely pass an object back and forth between two threads
我想以线程安全的方式在使用任意对象的两个线程之间建立一个简单的“协议”,而不是专门针对多线程。 该协议应该是只有线程之一拥有该对象,并且只有拥有者才能读/写该对象。 我在 此处阅读了有关事件的信息,但不确定该讨论是仅涉及单个字段还是整个对象。 以下两种解决方案是否适用于“所有权协议”?
1)使用BlockingQueue,以使对象通过队列传递到另一个线程。
2)“套利对象”不再那么随意了,因为我介绍了一个
volatile boolean ownedByThreadA;
与ownedByThreadA
是true
最初和线程A正在使用的对象。 完成后,线程A将false
写入ownedByThreadA
。 线程B轮询与此类似的变量
while (data.ownedByThreadA) {
doOtherThings();
}
dealWith(data);
我相当确定(1)是正确的解决方案。 我不确定(2)。 特别是对于(2),我想知道,如果遵循“用户协议”,那么是否只有一个volatile
足以满足一种正确的解决方案。
可以保证,在线程B看到!ownedByThreadA
之后,线程B必须在ownedByThreadA = false
之前对线程B可见。
您还必须小心如何更新data
变量本身(如果线程b将其更改为其他变量,并且该成员本身不是易失性,例如,您有一个bug),但是假设两个线程都在同一个实例上工作,您将得到正确的行为。
如果你需要在一次只有一个线程拥有特定的时刻,因此可以读/写对象,考虑增加synchronized
块是用来执行读取和写入数据到它的方法。
例如,假设您的对象是一组字符串,说“写”的意思是“向该集合添加一个字符串”,说“读”的意思是“获取一个集合中的字符串数”。
public class SetHolder {
private static Set<String> set = new HashSet<String>();
public static void writeData(String data) {
synchronized(set) {
set.add(data);
}
}
public int readData() {
synchronized(set) {
return set.size();
}
}
}
关于与挥发性标志您的解决方案:我不建议使用,因为检查if (ownedByThreadA) {
以及应执行的代码,使非原子操作,从而导致可能的竞争条件下,当ownedByThreadA
标志更改它的值,而此非原子操作尚未完成。
如果确实需要在两个线程之间传输对象或让两个线程通过某些对象交换,请考虑使用Exchanger
类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.