[英]Volatile needed if method is synchronized?
我有多个线程访问class Aufzahlen
并递增cc变量。 我想知道我是不是把cc放在volatile上但我的同步方法是否有任何错误空间? 由于cc变量一次只能访问一次。
线程是否仍然可以在自己的缓存中包含cc变量,因此它变得混乱? 我一直在运行这段代码示例,到目前为止没有发现任何错误。
public class Aufzahlen {
private int cc=1;
public synchronized void aufzahlen() throws InterruptedException {
cc = cc +1;
}
public synchronized void printa() {
// TODO Auto-generated method stub
System.out.println("Thread: " + Thread.currentThread() + "Zahl: " + cc);
}
{
这种方法不会失败。 如果每次访问字段时都进行同步,则每次线程持有相同的锁时,都可以看到对它的更改,如下所示:
来自Java Concurrency In Practice [ pdf ],图3.1
因此,使场不稳定是不必要的。 使用AtomicInteger
的getAndIncrement()
和incrementAndGet()
方法可能会更好,它们具有相同的目的,但具有更好的并发吞吐量(它们使用本机功能而不是锁定,它们专为完成此任务而设计) -但要确保给出AtomicInteger
本身的内存可见性(最简单的方法是使其最终 - 它不会使AtomicInteger
的值最终)。
public class Aufzahlen {
private final AtomicInteger atomicInt = new AtomicInteger(1); // set initial value with constructor argument
public void aufzahlen() {
atomicInt.incrementAndGet();
} // no need for synchronization because updates are atomic and are automatically visible
}
我可能在这篇文章中使用过一次或两次“原子”,这意味着没有两个线程可能同时执行相同的代码,换句话说,操作不能“分成”多个部分,多个线程可能是同时在里面。
+--- Function aufzählen() without synchronization and with i++ ---------------+
| |
| [Get i from field] --> [Increment i locally] --> [Write new value to field] |
| ^ ^ |
| | | |
| "Race condition", multiple threads could be at these stages |
| -> operation not atomic |
+-----------------------------------------------------------------------------+
我只是演示了什么不是原子的,你可以通过使用synchronized
来使这个操作成为原子(下一个线程需要等待第一个完成整个方法)或者你可以使用AtomicInteger
为你做这个原子性。
volatile
变量告诉编译器在读和写操作中永远不会将它们的值缓存在寄存器中。 仍然使用CPU缓存(L1,L2等)。
如果对此变量的所有访问(在类的单个实例中)都来自多个线程,则它们都应受到保护。
如果你有兴趣在没有同步的情况下从另一个线程读取这个cc
值,那么是的,让它变得volatile
。 这将有效地使同步成为写锁定。
由于同步块,源代码没有问题。 字段cc
将同时仅访问一个线程,因为两个不同的线程将不允许同时执行同步块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.