方法同步时需要波动?

时间:2015-12-27 08:52:53

标签: java multithreading volatile

我有多个线程访问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);
  }

{

3 个答案:

答案 0 :(得分:6)

1。能见度

此方法不会失败。如果每次访问字段时都进行同步,则每次线程持有相同的锁时,都可以看到对它的更改,如下所示:

enter image description here

来自Java Concurrency In Practice [pdf],图3.1

所以不必使该字段变得不稳定。使用AtomicIntegergetAndIncrement()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
}

2。原子

我可能在这篇文章中曾经使用过一次或两次“原子”,这意味着没有两个线程可能同时执行相同的代码,或者换句话说,操作不能“划分”为多个部分,即多个线程可以在同时进行。

+--- 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将同时只访问一个线程,因为两个不同的线程不允许同时执行同步块。