使用同步时会对性能产生影响。 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;
}
}
请告诉我这可能会破坏的情况?
答案 0 :(得分:11)
是的,你绝对可以。事实上,如果你看一下AtomicInteger
的源代码,它基本上就是他们所做的。 AtomicInteger.get
只返回value
,即volatile int
(link)。与你所做的和他们做的唯一真正的区别是他们使用CAS来增加而不是同步。在现代硬件上,CAS可以消除任何互斥;在较旧的硬件上,JVM会在增量周围添加某种互斥量。
易失性读取速度与非易失性读取速度一样快,因此读取速度非常快。
不仅如此,保证volatile
字段不会撕裂:请参阅JLS 17.7,其中指明volatile
long
和double
不是受撕裂的话。因此,您的代码只能使用long
和int
。
正如迭戈·弗雷纳所指出的那样,如果你得到“正确”的增值值,那么你可能看不到增量的结果 - 你会看到之前或之后。当然,如果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,当应用于方法时(就像在您的示例中那样),只允许单个线程一次输入该方法并阻止其他方法,直到执行完成。