我有多个线程访问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);
}
{
答案 0 :(得分:6)
此方法不会失败。如果每次访问字段时都进行同步,则每次线程持有相同的锁时,都可以看到对它的更改,如下所示:
来自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
为你做这个原子性。
答案 1 :(得分:0)
volatile
变量告诉编译器在读取和写入操作中都不会将它们的值缓存在寄存器中。仍然使用CPU缓存(L1,L2等)。
如果对此变量的所有访问(在类的单个实例中)都来自多个线程,则它们都应受到保护。
如果您有兴趣在没有同步的情况下从另一个线程读取此cc
值,那么请将其设为volatile
。这将有效地使同步成为写锁定。
答案 2 :(得分:0)
由于同步阻止,源代码没有问题。字段cc
将同时只访问一个线程,因为两个不同的线程不允许同时执行同步块。