易失性同步组合以提高性能

时间:2012-07-27 04:10:13

标签: java concurrency volatile synchronized

使用同步时会对性能产生影响。 volatile可以与synchronized结合使用以降低性能开销吗?例如,Counter的实例将在许多线程之间共享,每个线程都可以访问Counter的公共方法。在下面的代码中,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;
    }   
}

请告诉我这可能会破坏的情况?

4 个答案:

答案 0 :(得分:11)

是的,你绝对可以。事实上,如果你看一下AtomicInteger的源代码,它基本上就是他们所做的。 AtomicInteger.get只返回value,即volatile intlink)。与你所做的和他们做的唯一真正的区别是他们使用CAS来增加而不是同步。在现代硬件上,CAS可以消除任何互斥;在较旧的硬件上,JVM会在增量周围添加某种互斥量。

易失性读取速度与非易失性读取速度一样快,因此读取速度非常快。

不仅如此,保证volatile字段不会撕裂:请参阅JLS 17.7,其中指明volatile longdouble不是受撕裂的话。因此,您的代码只能使用longint

正如迭戈·弗雷纳所指出的那样,如果你得到“正确”的增值值,那么你可能看不到增量的结果 - 你会看到之前或之后。当然,如果get被同步,那么你从read线程中获得了完全相同的行为 - 你可以看到前增量或后增量值。所以这两种方式都是一样的。换句话说,说你不会看到它正在发生的价值是没有意义的 - 除非你的意思是撕裂,(a)你不会得到和(b)你永远不会想要的。 / p>

答案 1 :(得分:6)

1。我个人使用volatile synchronized相结合的机制。

2。可以单独使用 synchronized,而您将始终获得一致的结果,但使用        仅 volatile 不会始终产生相同的结果。

3。这是因为volatile关键字不是同步原语。 它只是防止缓存线程上的值,但它不会阻止两个线程修改相同的值并同时将其写回来。

4. volatile并行访问线程提供无锁,但是使用synchronized将允许只有一个线程获得访问此类以及该类中的所有同步方法。

5. 同时使用 volatile and synchronized即可...

volatile - 会将更改后的值反映给线程,并阻止缓存,

synchronized - 但是使用synchronized关键字,将确保只有一个线程可以访问该类的同步方法。

答案 2 :(得分:0)

调用getCount()时,您不会总是获得最实际的计数。 AtomicInteger可能适合您。

答案 3 :(得分:0)

使用两者都不会带来性能提升。 Volatile保证在通过防止缓存并行执行的线程读取/写入变量时变量的值是一致的。 Synchronized,当应用于方法时(就像在您的示例中那样),只允许单个线程一次输入该方法并阻止其他方法,直到执行完成。