I have two threads. One invokes the update method of a class that modifies a variable. Another invokes the update method of a class that reads the variable. Only one thread
Not only should variable
be volatile
, but you also want to protect your update
function with some sort of synchronization since ++variable
is not an atomic call. It is, after all, just syntactic sugar for
variable = variable + 1;
which is not atomic.
You should also wrap any calls that read variable in a lock of some sort.
Alternatively, use an AtomicInteger. It was made for this sort of thing (for just integer operations).
public class A
{
// initially had said volatile wouldn't affect this variable because
// it is not a primitive, but see correction in comments
public final AtomicInteger variable; // see comments on this issue of why final
public void update()
{
// Called by one thread constantly
variable.getAndIncrement(); // atomically adds one
}
public int retrieveValue()
{
return variable.get(); // gets the current int value safely
}
}
public class B
{
public A a;
public void update()
{
// Called by another thread constantly
int v = a.retrieveValue();
// Do algorithm with v...
}
}
For the more complex algorithms, as your recent edit assumes, use synchronization or locks.
If there is one and only one thread that writes to variable
you can get away with making it volatile
. Otherwise see the answer with AtomicInteger
.
Only volatile
will work in case of only one writing thread because there is only one writing thread so it always has the right value of variable
.
In this case I would use an AtomicInteger, however the generalised answer is that access to variable should be protected by a synchronized block, or by using another part of the java.util.concurrent package.
A couple of examples:
Using synchronized
public class A {
public final Object variable;
public void update() {
synchronized(variable) {
variable.complexAlgorithm();
}
}
}
public class B {
public A a;
public void update() {
sychronized(a.variable) {
consume(a.variable);
}
}
}
Using java.util.concurrent
public class A {
public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public final Object variable;
public void update() {
lock.writeLock().lock();
try {
variable.complexAlgorithm();
} finally {
lock.writeLock().unlock();
}
}
}
public class B {
public A a;
public void update() {
a.lock.readLock().lock();
try {
consume(a.variable);
} finally {
a.lock.readLock().unlock();
}
}
}
Use AtomicInteger
or synchronize
the access to be safe.