为什么使用原子变量访问比通过同步代码访问这些变量更有效?

时间:2016-02-18 12:27:35

标签: java synchronization shared-memory atomic synchronized

我是Java新手,正在尝试学习原子访问的概念。我在Java Tutorial Oracle中看到了以下声明。我的问题是:

  1. 为什么使用原子变量访问比通过同步代码访问这些变量更有效?

  2. 为什么使用原子变量访问需要程序员更加小心,以避免内存一致性错误。

  3. 我正在艰难地解决它。

      

    使用简单的原子变量访问比访问更有效   这些变量通过同步代码,但需要更多的关注   程序员避免内存一致性错误。是否额外   努力是值得的,取决于的大小和复杂性   应用

2 个答案:

答案 0 :(得分:1)

将变量声明为volatile意味着修改其值会立即影响变量的实际内存存储。编译器无法优化对变量的任何引用。这保证了当一个线程修改变量时,所有其他线程立即看到新值。 (这不一定适用于非易失性变量。)

声明一个原子变量保证对变量进行的操作以原子方式发生,即操作的所有子步骤都在它们执行的线程内完成,并且不会被其他线程中断。例如,增量和测试操作要求增加变量,然后与另一个值进行比较;原子操作保证这两个步骤都可以完成,就好像它们是一个不可分割/不可中断的操作一样。

同步对变量的所有访问只允许一次一个线程访问变量,并强制所有其他线程等待访问线程释放其对变量的访问权。

同步访问类似于原子访问,但原子操作通常在较低级别的编程中实现。此外,完全可以同步一些对变量的访问,并允许其他访问不同步(例如,将所有写入同步到变量,但不同步它的任何读取)。

原子性,同步性和波动性是独立属性,但通常组合使用以强制执行正确的线程协作以访问变量。

答案 1 :(得分:1)

回答(1): 对于读访问,无论是原子还是非原子,同步或非同步都无关紧要。 对于写访问,原子变量不需要锁写,因为对变量的所有更新都是原子的(发生或未完全发生)例如:假设您想在多线程应用程序中执行i ++并且多个线程可以调用它,您需要synchnorzied i ++调用(因为它被设置为3个注册表级别调用,你知道它可以在注册表级别调用的任何点上进行上下文切换,即使在中间)也可以避免脏读和写入不一致。 而原子变量只有1个注册表级别的调用(由于添加了额外的寄存器,我们的语言利用它)。 由于同步开销(获取监视器锁并在此后释放),原子变量访问比通过同步代码访问这些变量更有效

回答(2): java中的所有对象都需要程序员更加小心,以避免内存一致性错误,无论是否为Atomic都无关紧要。 虽然原子变量的兄弟可以是原始的而不是对象,但它不属于对象类别,因此不需要处理内存一致性错误 每个对象在多线程应用程序中需要避免内存一致性错误的原因是因为每个线程堆栈在线程堆栈上本地缓存对象的副本(运行时优化)可能导致与另一个线程修改的堆的实际副本不同步(即使在相同的代码但不同的线程堆栈)。要避免的一个解决方案是对该对象使用 volatile ,这可以经常被另一个线程更改。此外,本地副本会尝试与堆副本同步,但如果您的线程以比同步更快的速度访问它,则会出现问题。

希望这有助于您理解原子和内存访问概念。