喜欢同步到volatile

时间:2015-09-28 08:06:53

标签: java multithreading synchronization volatile

我已经阅读了这篇answer,最后写了以下内容:

  

任何可以使用volatile的东西都可以通过synchronized来完成,但是   反之亦然。

目前尚不清楚。 JLS 8.3.1.4定义了volatile字段,如下所示:

  

字段可以声明为volatile,在这种情况下是Java Memory Model   确保所有线程都看到变量的一致值   (§17.4)。

因此,volatile字段与内存可见性有关。另外,据我所提到的答案,读取和写入易失性字段是同步的。

同步反过来保证只有一个线程可以访问同步块。正如我所知,它与内存可见性无关。我错过了什么?

4 个答案:

答案 0 :(得分:7)

事实上,同步也与内存可见性有关,因为JVM在synchronized块的出口处添加了 内存屏障 。这确保了同步块中线程的写入结果可以保证通过另一个线程一次第一个线程退出同步块时可见。

注意:关注@PaŭloEbermann的评论,如果另一个线程通过读取内存屏障(例如通过进入同步块),它们的本地缓存将不会失效,因此它们可能会读取旧的价值。

同步块的退出是此文档中 发生在 之前:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

寻找这些摘录:

  

一个线程写入的结果保证对a可见   只有在写入操作发生之前,才由另一个线程读取   读操作。

  

监视器的解锁(同步块或方法退出)   发生在每个后续锁定之前(同步块或方法)   那个监视器的入口)。而且因为发生在之前的关系   是传递的,解锁之前线程的所有动作   发生 - 在任何线程锁定之后的所有操作之前发生   监视。

答案 1 :(得分:2)

同步和易失性不同,但通常它们都用于解决相同的常见问题。

同步是为了确保在给定的时间点只有一个线程将访问共享资源。

然而,这些共享资源通常被声明为volatile,这是因为,如果一个线程更改了共享资源值,它也必须在另一个线程中更新。但是没有volatile,运行时只需通过读取缓存中的值来优化代码。那么volatile的作用是,每当任何线程访问volatile时,它都不会从缓存中读取值,而是实际从实际内存中获取它并使用相同的内容。

正在浏览log4j代码,这就是我找到的内容。

/**
 * Config should be consistent across threads.
 */
protected volatile PrivateConfig config;

答案 2 :(得分:1)

那是错的。同步与内存可见性有关。每个线程都有自己的缓存。如果你有一个锁,缓存就是refresehd。如果您释放锁定,则缓存将流入主存储器。

如果你读了一个volatile字段,那么还有一个刷新,如果你写一个volatile字段就会有一个刷新。

答案 3 :(得分:1)

如果多个线程写入共享的volatile变量,并且还需要使用它的先前值,则可以创建race condition。所以此时你需要使用同步。

  

...如果两个线程都在读取和写入共享变量,那么使用volatile关键字是不够的。在这种情况下,您需要使用synchronized来保证变量的读取和写入是原子的。读取或写入volatile变量不会阻止线程读取或写入。为此,您必须在关键部分周围使用synchronized关键字。

有关volatile的详细教程,请参阅 'volatile' is not always enough