java - volatile 同步组合以提高性能

标签 java concurrency volatile synchronized

使用同步会影响性能。 volatile 能否与 synchronized 结合使用以降低性能开销?例如,Counter 的实例将在多个线程之间共享,每个线程都可以访问 Counter 的公共(public)方法。在下面的代码中,volatile 用于 getter,synchronized 用于 setter

public class Counter
{
    private volatile int count;

    public Counter()
    {
        count = 0;
    }

    public int getCount()
    {
        return count;
    }

    public synchronized void increment()
    {
        ++count;
    }   
}

请告诉我这可能会在哪种情况下中断?

最佳答案

是的,你绝对可以。事实上,如果您查看AtomicInteger 的源代码,它们本质上就是这样做的。 AtomicInteger.get 仅返回 value,这是一个 volatile int ( link )。与您所做的和他们所做的唯一真正的区别是他们使用 CAS 进行增量而不是同步。在现代硬件上,CAS 可以消除任何互斥;在较旧的硬件上,JVM 将在增量周围放置某种互斥体。

volatile 读取与非 volatile 读取速度差不多,因此读取速度会非常快。

不仅如此,volatile 字段也保证不会撕裂:参见 JLS 17.7 ,它指定 volatile longdouble 不受单词撕裂的影响。因此,您的代码既可以使用 long 也可以使用 int

正如 Diego Frehner 指出的那样,如果您在增量发生时“恰好”获得值,您可能看不到增量的结果——您将看到之前或之后的结果。当然,如果 get 是同步的,您将拥有与读取线程完全相同的行为——您将看到增量前或增量后的值。所以这两种方式实际上是一样的。换句话说,说你不会看到正在发生的值(value)是没有意义的——除非你的意思是撕裂,(a) 你不会得到,(b) 你永远不会想要。

关于java - volatile 同步组合以提高性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11681326/

相关文章:

java - 对于一个类的多个实例,Volatile 关键字无法按预期工作

java - 为什么不允许使用 volatile final 字段?

java - 使用 maven 命令运行测试时传递用户名

java - 经常使用但具有并发性的 HashMap

java - Hibernate HQL LEFT JOIN 的执行与等效 SQL 不同

c++ - 什么 C++11 <atomic> 操作/内存顺序保证新鲜度?

loops - 为什么无限循环不递增整数?

c# - 为什么 C# volatile 不保护读写重排序?

java - 无法在同一类的对象上使用方法

java - 类名必须在方法之前,必须是 MatcherAssert.assertThat() 而不仅仅是 assertThat()?