1

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

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

2)“任意对象”不再那么随意了,因为我引入了一个

  volatile boolean ownedByThreadA;

最初,线程 A 正在使用该对象ownedByThreadAtrue完成后,线程 Afalse写入ownedByThreadA. 线程 B 轮询与此类似的变量

while (data.ownedByThreadA) {
  doOtherThings();
}
dealWith(data);

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

4

2 回答 2

1

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

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

于 2014-04-03T12:07:57.680 回答
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) {和应该执行的代码会进行非原子操作,这会导致可能的竞争条件,当ownedByThreadA标志更改其值时,而此非原子操作尚未完成的。

如果确实需要在两个线程之间传递一个对象,或者让两个线程通过一些对象进行交换,可以考虑使用Exchangerclass.

于 2014-04-03T08:48:36.510 回答