Reputation:
In a class on Java Concurrency I was advised to use the following code for a counter in a multithreaded application
private volatile int count;
I was asking myself if I could use the volatile keyword with the wrapper class Integer instead of the primitive type int (see below):
private volatile Integer count;
Would it be correct to use the Integer wrapper class in this case?
Upvotes: 3
Views: 445
Reputation: 2800
Strictly speaking, it would be correct. If one thread sets a new count, every other thread reading it will get the new value.
You will run into issues if two threads write the value at the same time since there is never a guarantee that the value that you last read for the counter is the value when you go to write the counter. For example, if you have two threads and a counter that is starting off at 0.
Thread 1: int temp = count.intValue(); //temp = 0;
Thread 2: int temp = count.intValue(); //temp = 0;
Thread 1: count = new Integer(temp+1); //count = 1;
Thread 2: count = new Integer(temp+1); //count = 1;
As you can see, you incremented the counter twice but the value only increased by 1. The same behavior can occur even if you change the command to
count = new Integer(count.intValue() + 1);
Since the JVM still needs to read in the value, increment it, and write it out, each of which is at least 1 cycle.
To avoid this, either use an AtomicInteger
(which does not need to be volatile), as suggested by @chrylis, or use synchronization and/or locks to make sure you never have 2 threads writing the count.
Upvotes: 1
Reputation: 96385
The Integer class is immutable, so when the count changes it gets a reference to a new Integer, and the volatile keyword makes sure the new reference is visible across threads.
But if you want the updates to be atomic then using AtomicInteger would be a better choice, because incrementing based on the current value will not be safe otherwise.
Upvotes: 1
Reputation: 6306
Marking as volatile is only correct if the only thing you are doing outside of a synchronized region is setting or getting the value. ANY attempt at "relative" math (incrementing, decrementing, etc.) is not thread safe. To do any of that sort of work requires either synchronization or use of an AtomictInteger.
Upvotes: 1
Reputation: 31648
Actually both versions are poor designs.
From Java Concurrency in Practice p. 39:
...the semantics of
volatile
are not strong enough to make the increment operation (count++) atomic, unless you can guarantee that the variable is written only from a single thread. (Atomic variables do provide atomic read-modify-write support and can often be used as "better volatile variables")
So I recommend using AtomicInteger
private AtomicInteger count;
Upvotes: 4