我是否需要在读写器方案中使两个变量都不稳定?

时间:2015-02-25 04:38:17

标签: java concurrency concurrent-programming

我们有2个主题。一个是读者。另一个是作者线程,他们分享这两个变量:

Object data
boolean ready

我是否需要使两者都易变?是否足以让他们做好准备。易失性

write() {
    data = <some data>
    ready = true;
}

read() {
    if (ready) {
        consume(data);
        ready = false;
    } 
}

我是否需要使这两个变量都不稳定?

基于我对java内存模型的有限描述,我认为我只需要准备好&#39;在读/写之前所有代码都是易变的&#39;准​​备好了发生在 - 准备好&#39;读/写之后的代码之前。变量?

更新:出于此问题的目的,假设原子性不是问题。数据的生成和消费是原子的。

5 个答案:

答案 0 :(得分:1)

挥发物有助于发出信号,但不是原子性。您需要原子性,以防数据在消耗时更新,但尚未设置就绪。

答案 1 :(得分:1)

正如其他人已经明确的原子性一样,你可以通过使用ReadWriteLock来增加并发性。更多详情请见:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html

在这种情况下,可能有多个读取器线程,写锁定将是独占的。

答案 2 :(得分:0)

您的问题与SO上的其他问题类似。

正如我所说,如果数据就绪仅由一个线程更新,那么volatile适用于 BOTH 。 Atomic适用于多个作家。

答案 3 :(得分:0)

您的理解是正确的。

当线程1写入易失性变量并且随后线程2读取该易失性变量时,易失性读取之前线程1可见的所有变量在易失性读取之后变为可见。就像线程1离开同步块一样,然后线程2进入。

但它不是一种提供可见性的推荐方法,因为它没有明确地显示自己进入/退出同步块或获取/释放锁定。

答案 4 :(得分:0)

在您的示例中,易失性变量对于像 ready 这样的状态标志很方便,但只保证以线程安全的方式访问该值,并不保证其余的块按顺序执行。 / p>

在您的示例中,写入(数据)读取()操作可以并行执行,执行时间消耗(数据)可能会在写入(数据)的第二次调用后完成 read(),这会将 ready 变量设置为false,即使它对于由写入(数据)的第二次调用设置的新数据,预计是正确的。

例如:

线程1开始:写入(data1)

线程1结束:// ready:true,data = data1

线程2开始: read() // consume(data1)需要一段时间。

线程3开始:写入(data2) // ready = true,data = data2

线程2结束:读取() //消耗(data2)完成,ready = false,data = data2