Java 变量的非同步读/写可能导致数据竞争?

Java 变量的非同步读/写可能导致数据竞争?,java,concurrency,thread-safety,data-race,non-thread-safe,Java,Concurrency,Thread Safety,Data Race,Non Thread Safe,在Jack Shirazi的著作中写道: 这意味着,只要变量的访问和更新不是long或double,它们就会自动同步。如果一个方法只包含一个变量访问或分配,那么就没有必要为了线程安全而使它同步,也没有理由为了性能而不这样做。线程安全性进一步扩展到独立于任何其他变量值访问或分配变量的任何语句集 根据上面的描述,flag=true之类的操作始终是原子操作,不需要同步 然而,以下情况被视为数据竞争: 类DataRaceExample{ 静态布尔标志=false;//w0 静态空隙上升滞后{ flag=

在Jack Shirazi的著作中写道:

这意味着,只要变量的访问和更新不是long或double,它们就会自动同步。如果一个方法只包含一个变量访问或分配,那么就没有必要为了线程安全而使它同步,也没有理由为了性能而不这样做。线程安全性进一步扩展到独立于任何其他变量值访问或分配变量的任何语句集

根据上面的描述,flag=true之类的操作始终是原子操作,不需要同步

然而,以下情况被视为数据竞争:

类DataRaceExample{ 静态布尔标志=false;//w0 静态空隙上升滞后{ flag=true;//w1 } 公共静态无效字符串…args{ ForkJoinPool.commonPool.executeDataRaceExample::raiseFlag; while!flag;//r_i,其中i∈ [1,k,k可能是无限的 System.out.printflag;//r } } 作者说:

现在,所有的执行都有数据竞争,因为标志不是易变的


这两篇文章之间的冲突让我很困惑。

在第二个例子中,循环要么不会运行,要么永远运行

这是因为变量标志在第一次检查时只读取一次


如果flag是易失性的,则每次都会从内存中读取。这允许另一个线程更改flag的值,循环将看到它。

在第二个示例中,循环将不会运行或永远运行

这是因为变量标志在第一次检查时只读取一次

如果flag是易失性的,那么每次都会从内存中读取它。这允许另一个线程更改flag的值,循环将看到它。

Jack Shirazi是错误的

对基本变量(如int)的访问和更新是原子的,但不是同步的

因为它是原子的,所以可以通过使其易失性使其完全线程安全。否则,运行在不同内核上的其他线程可能会看到过时的值,因为CPU缓存尚未刷新。

Jack Shirazi错了

对基本变量(如int)的访问和更新是原子的,但不是同步的


因为它是原子的,所以可以通过使其易失性使其完全线程安全。否则,运行在不同内核上的其他线程可能会看到过时的值,因为CPU缓存尚未刷新。

Jack Shirazi试图指出的一点是,对double和long以外的基元类型的非易失性访问可以保证可以根据JMM原子地执行。因此,不需要同步来防止(例如)并发访问时的读写中断


出现这种混乱是因为他的书早于JSR-133,并且他使用了自动同步等术语,这与JMM中的现代同步概念不符。

Jack Shirazi试图指出的一点是,除了double和long之外,对原语类型的非易失性访问保证是由原子执行的因此,不需要同步来防止,例如,在存在并发访问的情况下,读取和写入被破坏


这种混乱是因为他的书早于JSR-133,他使用了自动同步这样的术语,这与JMM中的现代同步概念不符。

如果布尔的读/写是原子的,那么在另一个thead中读写应该总是可见的。我知道cpu有缓存,但如果java保证原子操作的易失性,在这里应该不是问题,这里不需要易失性。问题是,如果标志不是易失性的,它只从内存中读取一次。即使它是从另一个线程更改的,循环也不会重新读取changes变量。是的,读取是原子的。但是,这只是意味着从内存中读取在一个线程中完成保证单操作。这并不意味着它总是从内存中读取。但您使用的是普通布尔值,而不是原子布尔值。变量标志只能读取一次。规范不要求此行为。如果布尔值的读取/写入是原子的,则写入操作应始终可见,以便在另一个thead中读取。我知道cpu有缓存,但是如果java保证原子操作的可视性,那么这里应该没有问题,这里也不需要volatile。问题是,如果标志不是volatile,它只从内存中读取一次。即使它是从另一个线程更改的,循环也不会重新读取changes变量。是的,读取是原子的。然而,这只是意味着从内存中读取是在保证的单个操作中完成的。这并不意味着它总是从内存中读取。但您使用的是普通布尔值,而不是原子布尔值。变量标志只能读取一次。规范确实如此
不需要这种行为。他并不是真的错了,他不幸地使用了非标准的前JSR-133术语来描述基元类型的读/写原子性。他并不是真的错了,他不幸地使用了非标准的前JSR-133术语来描述基元类型的读/写原子性。