12

使用同步时会对性能产生影响。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

4 回答 4

11

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

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

不仅如此,volatile还保证字段不会撕裂:参见JLS 17.7,它指定volatile longs 和doubles 不受单词撕裂的影响。因此,您的代码可以与 alongint.

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

于 2012-07-27T05:03:39.017 回答
6

1.我个人使用过这种volatile 结合的 synchronized机制。

2.可以单独使用 synchronized你总是会得到一致的结果,但单独使用 volatile 不会总是产生相同的结果。

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

4. volatile在没有锁的情况下给线程并发访问,但随后使用synchronized只允许一个线程访问 this 以及类中的所有同步方法。

5.两者都使用 会做到这volatile and synchronized一点....

volatile -将更改的值反映到线程,并防止缓存,

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

于 2012-07-27T04:46:41.530 回答
0

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

于 2012-07-27T04:15:25.533 回答
0

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

于 2012-07-27T04:18:34.707 回答