简体   繁体   English

方法同步时需要波动?

[英]Volatile needed if method is synchronized?

I have multiple threads accessing class Aufzahlen and incrementing the cc variable. 我有多个线程访问class Aufzahlen并递增cc变量。 I wonder if i don't put cc on volatile but my method on synchronized is there any room for error here? 我想知道我是不是把cc放在volatile上但我的同步方法是否有任何错误空间? Since the cc variable will only be accessed once at a time. 由于cc变量一次只能访问一次。

Is it still possible for threads to have the cc variable in there own cache and therefor mess with it? 线程是否仍然可以在自己的缓存中包含cc变量,因此它变得混乱? I had been running this code example for a while now and didn't find any errors so far. 我一直在运行这段代码示例,到目前为止没有发现任何错误。

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);
  }

{

1. Visibility 1.可见性

This method will not fail. 这种方法不会失败。 If you synchronize every time you access a field, changes to it are guaranteed to be visible every time a thread holds the same lock, as demonstrated below: 如果每次访问字段时都进行同步,则每次线程持有相同的锁时,都可以看到对它的更改,如下所示:

在此输入图像描述

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

So it is not neccessary to make the field volatile. 因此,使场不稳定是不必要的。 You are probably much better off by using AtomicInteger 's getAndIncrement() and incrementAndGet() methods, which serve the same purpose, but with better concurrency throughput (they use native functionality instead of locking, they have been designed for exactly this task) - but make sure that memory visbility of the AtomicInteger itself is given (the easiest way to do this is make it final - it won't make the AtomicInteger 's value final). 使用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. Atomicity 2.原子性

I might have used "atomic" once or twice in this post, it means that no two threads may be concurrently executing the same code, or, in other words, that the operation cannot be "divided" into multiple parts that multiple threads could be inside of concurrently. 我可能在这篇文章中使用过一次或两次“原子”,这意味着没有两个线程可能同时执行相同的代码,换句话说,操作不能“分成”多个部分,多个线程可能是同时在里面。

+--- 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                                          |
+-----------------------------------------------------------------------------+

I just demonstated what is not atomic, you can make this operation atomic by using synchronized (the next thread needs to wait for the first to finish the whole method) or you could use AtomicInteger which does this atomicity for you. 我只是演示了什么不是原子的,你可以通过使用synchronized来使这个操作成为原子(下一个线程需要等待第一个完成整个方法)或者你可以使用AtomicInteger为你做这个原子性。

volatile variables tell the compiler to never cache their value in a register in both read and write operations. volatile变量告诉编译器在读和写操作中永远不会将它们的值缓存在寄存器中。 CPU caches (L1, L2, etc.) are still used. 仍然使用CPU缓存(L1,L2等)。

If all accesses to this variable (in a single instance of the class) are coming from multiple threads, they all should be protected. 如果对此变量的所有访问(在类的单个实例中)都来自多个线程,则它们都应受到保护。

If you're interested to read this cc value from another thread without synchronization, then yes, make it volatile . 如果你有兴趣在没有同步的情况下从另一个线程读取这个cc值,那么是的,让它变得volatile This will effectively make the synchronization a write-lock. 这将有效地使同步成为写锁定。

There is no problem in your source code due to synchronized block. 由于同步块,源代码没有问题。 Field cc will be accessed only one thread at the same time because two different threads will be not allow to execute a synchronized block concurrently. 字段cc将同时仅访问一个线程,因为两个不同的线程将不允许同时执行同步块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM