Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Volatile needed if method is synchronized?

I have multiple threads accessing class Aufzahlen and incrementing the cc variable. I wonder if i don't put cc on volatile but my method on synchronized is there any room for error here? Since the cc variable will only be accessed once at a time.

Is it still possible for threads to have the cc variable in there own cache and therefor mess with it? 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);
  }

{
like image 410
Timo N. Avatar asked Mar 14 '23 18:03

Timo N.


1 Answers

1. Visibility

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:

enter image description here

From Java Concurrency In Practice [pdf], figure 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).

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

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.

like image 64
randers Avatar answered Mar 28 '23 06:03

randers