Java在澄清之前发生,以及如何在两个线程之间来回安全地传递对象

时间:2014-04-03 08:39:22

标签: java multithreading happens-before

我想在两个使用任意对象的线程之间建立一个简单的“协议”,而不是专门针对多线程,以线程安全的方式。协议应该是只有一个拥有对象的线程,只有所有者可以读/写对象。我阅读了有关发生之前 here的信息,但不太确定讨论是仅涉及单个字段还是整个对象。以下两种解决方案是否适用于“所有权协议”?

1)使用BlockingQueue,使对象通过队列传递给另一个线程。

2)“仲裁对象”不再那么随意,因为我引入了

  volatile boolean ownedByThreadA;

最初ownedByThreadAtrue,而线程A正在使用该对象。完成后,线程A将false写入ownedByThreadA。线程B轮询类似于此

的变量
while (data.ownedByThreadA) {
  doOtherThings();
}
dealWith(data);

我很确定(1)是正确的解决方案。对于(2)我不太确定。特别是对于(2)我想知道只要一个volatile就足以找到正确的解决方案,只要遵守“用户协议”。

2 个答案:

答案 0 :(得分:1)

保证线程A在ownedByThreadA = false之前完成的每次写入必须在线程B看到!ownedByThreadA后可见。

您还必须小心如何更新data变量本身(如果线程b将其更改为其他内容并且该成员本身不是易失性的,例如您有错误),但假设两个线程都在同一个实例上工作,你得到了正确的行为。

答案 1 :(得分:0)

如果您需要在特定时刻只有一个线程拥有并因此可以读/写对象,请考虑将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();
        }
    }
}

关于使用volatile标志的解决方案:我不建议使用它,因为检查if (ownedByThreadA) {和应该执行的代码进行非原子操作,导致可能的竞争条件,{{1} } flag更改其值,而此非原子操作尚未完成。

如果您确实需要在两个线程之间传输对象或让两个线程通过某些对象进行交换,请考虑使用ownedByThreadA类。