Java 同步跨线程共享但未并发访问的对象

Java 同步跨线程共享但未并发访问的对象,java,concurrency,volatile,Java,Concurrency,Volatile,假设我有一个带有字段数据的共享对象。多个线程将共享对此对象的引用,以便访问该字段。不过,线程从不同时访问对象。我是否需要将数据声明为易失性 这种情况如下: 类计数器定义一个唯一的字段值和一个方法增量 一个线程递增计数器,然后生成另一个递增计数器的线程,等等 鉴于程序的逻辑,不存在对计数器的并发访问。但是,计数器是跨多个线程共享的。计数器必须是易失性的吗 这种情况的另一种变体是,当多个线程操作一个对象X时,该对象X是纯数据,但通过另一个依赖于并发控制的对象Y交替执行(因此X永远不会被并发访问)

假设我有一个带有字段
数据的共享对象。多个线程将共享对此对象的引用,以便访问该字段。不过,线程从不同时访问对象。我是否需要将
数据
声明为易失性

这种情况如下:

  • 计数器
    定义一个唯一的字段
    和一个方法
    增量
  • 一个线程递增计数器,然后生成另一个递增计数器的线程,等等
鉴于程序的逻辑,不存在对计数器的并发访问。但是,计数器是跨多个线程共享的。计数器必须是易失性的吗


这种情况的另一种变体是,当多个线程操作一个对象X时,该对象X是纯数据,但通过另一个依赖于并发控制的对象Y交替执行(因此X永远不会被并发访问)(
wait
notify
synchronize
)。对象X的字段是否应该是可变的

Java内存模型和字节码重新排序不能保证后续线程将看到计数器的递增值。所以,如果您使用单线程—您不需要对volatile执行任何操作,但是如果多个线程可能从变量读取某些内容—您需要确保使用volatile或syncrhonization/locks对其他线程的更改的可见性


start方法设置了障碍,所以可见性是有保证的——并且可能发生的情况是,您不需要那些易变的东西。但是我还是要添加它。

Java内存模型和字节码重新排序不能保证后续线程将看到计数器的递增值。所以,如果您使用单线程—您不需要对volatile执行任何操作,但是如果多个线程可能从变量读取某些内容—您需要确保使用volatile或syncrhonization/locks对其他线程的更改的可见性


start方法设置了障碍,所以可见性是有保证的——并且可能发生的情况是,您不需要那些易变的东西。但是我还是要补充一下。

对于任何在Java中进行并发处理的人来说,强烈建议学习Java内存模型的整个JLS章节,事实上这是强制性的。具体而言,您的案例包含在

“启动线程的操作与它启动的线程中的第一个操作同步。”


这意味着对于第一个场景,您不需要
volatile
。然而,最好的做法是让它对将来的代码更改具有健壮性。您确实应该有一个很好的理由不要使用
volatile
,这只有在极高的读取速率(至少每秒数百万次)的情况下才会出现

对于在Java中执行并发的任何人,强烈建议学习Java内存模型的整个JLS章节,事实上这是强制性的。具体而言,您的案例包含在

“启动线程的操作与它启动的线程中的第一个操作同步。”


这意味着对于第一个场景,您不需要
volatile
。然而,最好的做法是让它对将来的代码更改具有健壮性。您确实应该有一个很好的理由不要使用
volatile
,这只有在极高的读取速率(至少每秒数百万次)的情况下才会出现

你在柜台上只讲了部分故事。计数器的递增部分似乎很好——正如Marko指出的,Thread.start处有一个HB边。但是谁在看这个柜台?如果是这些衍生线程之外的任何人,并且您关心看到最新的值,那么该字段需要是可变的。如果计数器是一个
长的
(或
双精度的
),即使你不关心过时的值,你也需要它是易变的,因为否则你可能会被字撕裂。

你只讲了计数器的部分故事。计数器的递增部分似乎很好——正如Marko指出的,Thread.start处有一个HB边。但是谁在看这个柜台?如果是这些衍生线程之外的任何人,并且您关心看到最新的值,那么该字段需要是可变的。如果计数器是一个
长的
(或
双精度的
),即使你不关心过时的值,你也需要它是易变的,因为否则你可能会被单词撕裂。

关于问题的第二部分:如果你不在变量X上使用volatile,给定线程可能总是使用变量值的本地缓存版本。使用变量Y作为锁可以很好地确保两个线程不会同时写入X,但不能保证其中一个线程不会查看过时的数据


来自JLS:“对易失性变量v的写入与任何线程对v的所有后续读取同步”。我阅读这篇文章的方式是,除了v.

关于问题的第二部分:如果不在变量X上使用volatile,那么给定的线程可能总是使用变量值的本地缓存版本,规范对读取其他变量没有任何保证。使用变量Y作为锁可以很好地确保两个线程不会同时写入X,但不能保证其中一个线程不会查看过时的数据


来自JLS:“对易失性变量v的写入与任何线程对v的所有后续读取同步”。我阅读这篇文章的方式是,规范没有提供对除v之外的其他变量的读取的保证。

只有在发生之前的关系时,来自线程的突变才会保证对其他线程可见