【问题标题】:Correct understanding of concepts like volatile, syncronized and AtomicReference?对 volatile、syncronized 和 AtomicReference 等概念的正确理解?
【发布时间】:2013-08-25 11:36:38
【问题描述】:

我想确保我正确理解了这些概念。解释/确认将对我有很大帮助,我相信许多其他程序员。 以下是我对这些概念的理解,来自我的调查:

  1. 当您想在多个线程之间共享一个变量时使用易失性。 a) 声明一个(线程之间共享的)变量 volatile 和 not 有什么区别? b) 我们是否应该总是在从不同线程访问它时声明它是 volatile 的? c) 同步一个 volatile 变量有意义吗?

  2. AtomicReference 是一个包装我们的对象并提供一些原子操作的类(compareAndSet、lazySet 和weakCompareAndSet)。这就是全部,没有同步,什么都没有。 a) 声明一个 AtomicReference volatile 有意义吗? b) 但是同步呢?因为 AtomicReference.get 既不同步也不同步?

  3. 同步是一个概念,它意味着对多个线程之间共享的变量进行顺序访问。它可以通过实例和类来完成。同步可以添加到方法头或代码块中。我希望这里没有谜团:)

问候, 奥勒良

【问题讨论】:

标签: java multithreading synchronization volatile atomicreference


【解决方案1】:

a) 声明一个(线程之间共享的)变量 volatile 和不声明有什么区别?

如果它不是易失性的,那么一个线程对它的写入可能永远不会被任何其他线程看到。

b) 我们是否应该总是在从不同线程访问它时声明它是 volatile 的?

除非它总是从同步块访问。

c) 同步 volatile 变量有意义吗?

确实如此,但前提是 volatile 变量也在任何同步块之外被访问。

a) 声明一个 AtomicReference volatile 有意义吗?

如果您打算在运行时更改实例,它肯定会这样做。但是,通常最好有一个final AtomicReference

b) 但是同步呢?因为 AtomicReference.get 既不同步也不同步?

同步 AtomicReference 访问违背了其无锁多线程的目的。选择同步或 AtomicReference。

【讨论】:

  • 但是由于 AtomicReference 的 get 和 set 没有同步,如果从多个线程访问它们,我们不能把事情搞砸吗?在我看来,AtomicReference 的唯一工作就是以原子方式执行这 3 种方法(compareAndSet、lazySet 和 weakCompareAndSet),仅此而已。我错了吗?
  • 我这么说是因为 Unsafe 类只用在这 3 种方法中,而且我在任何地方都看不到任何同步块,谢谢
  • 是的,从调用线程和任何其他线程的角度来看,这些操作都是原子的。它们构成了无锁多线程的基本元素。如果这些操作的细粒度不足以满足某个用例,那么 AtomicReference 不适合它,根本不应该使用。
  • 在下面,AtomicReference 使用了一个 volatile 成员,确保 get() 和 set() 以及类似的操作正在访问非线程特定的内存。这就是它在没有同步的情况下实现线程安全的方式。正如 Marko 和 ScottB 所说,实际上只有两种方法可以保证特定线程看到特定变量的“真实”(非线程特定)值:该变量被声明为“volatile”,这意味着它应该不会缓存在线程特定的内存中,或者该变量由同步块保护(所有线程特定的内存在同步时更新)。
【解决方案2】:

当你想在多个人之间共享一个变量时使用易失性 线程。 a) 声明 a 有什么区别(在 线程)变量易失性而不是? b) 我们是否应该总是声明它 volatile 在我们从不同的线程访问它? c) 它使 同步 volatile 变量是否有意义?

要了解volatile,思考现代计算机系统硬件的架构很有用。

为了提高性能,每个处理器或核心都有自己的本地内存缓存。此缓存中存在的数据对于特定处理器是本地的,对其他处理器不可见。此外,几乎任何级别的数据缓存都可以存在,包括 JVM 本身。

当您以这种方式考虑线程时,即可以在处理器之间划分的执行单元时,很容易理解 Java 内存模型的一个非常重要的事实:

无法保证在一个线程中对共享变量所做的更改将对访问同一变量的其他线程可见(不同步)。

再次假设,更新共享变量的数据仍位于其他内核无法使用的本地处理器缓存中(因此,在它们上执行的其他线程也无法使用)。

volatile 关键字为您提供了一种保证共享变量的更改立即写入内存的方法,以便它们发生的更改对其他线程可见。 Volatile 在简单的情况下很有用,虽然它提高了数据的活性,但它不能保证原子性,因此不能保证共享变量上的竞争条件仍然不会发生。

如果将一个对象从一种逻辑状态转变为另一种需要多个步骤,则必须同步对对象状态的访问以保持原子性(更新完全发生或根本不发生)即使状态转换仅涉及声明为volatile 的变量。

【讨论】:

  • Volatile 本身不提供原子性保证,但设置引用确实保证了原子性,因此如果所有需要保持最新和一致的只是单个引用,那么 volatile 就足够了(AtomicReference.get( ) 和 .set() 只是对 volatile 字段引用进行操作)。因此,如果您担心特定的共享变量,那么 volatile 很好,但如果您有两个或更多变量需要保持同步,或者正在更新“volatile”对象中的值,那么您将需要同步或其他锁定.
猜你喜欢
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-04
  • 2020-06-25
  • 1970-01-01
相关资源
最近更新 更多