The java meomry model mandates that synchronize
blocks that synchronize on the same monitor enforce a before-after-realtion on the variables modified within those b
Yanamon, I am not sure you are correct - but for different reasons than the argument you are making.
The unguardedVariable variable may be re-ordered in thread "a" such that its value is set to 10 after memoryBarrier is set to true.
"There is no guarantee that operations in one thread will be performed in the order given by the program, as long as the reordering is not detectable within that thread - even if the reordering is apparent to other threads"
Java Concurrency in Practise, Brian Goetz, p34
UPDATED: what I said is true in the case of the old memory model. So, if you want write-once-run-anywhere then my argument stands. However, in the new memory model, it is not the case as the semantics surrounding re-ordering of non-volatile variables in the presence of volatile access has become stricter (see http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile).
Beyond the question of what the semantics of the memory model guarantees, I think there are a few problems with the code you are posting.
Lock
implementation, you don't have need to use the synchronized
block.Lock
is to do so in a try-finally block to prevent accidental unlocking of the lock (since the lock is not automatically released when entering whatever block you are in, as with the synchronized
block).You should be using a Lock
with something resembling:
lock.lock();
try {
//do stuff
}
finally {
lock.unlock();
}
From the API-doc:
All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in The Java Language Specification, Third Edition (17.4 Memory Model):
* A successful lock operation has the same memory synchronization effects as a successful Lock action. * A successful unlock operation has the same memory synchronization effects as a successful Unlock action.
Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.
Reading and writing volatile variables now enforces happens before and happens after operation ordering. Writing to a volatile variable has the same effect as releasing a monitor and reading a variable has the effect as acquiring a monitor. The following example makes it a little more clear:
volatile boolean memoryBarrier = false;
int unguardedValue = 0;
//thread a:
unguardedValue = 10;
memoryBarrier = true;
// thread b
if (memoryBarrier) {
// unguardedValue is guaranteed to be read as 10;
}
But that all being said the sample code you provided did not look like it was really using the ReentrantLock as it was designed to be used.
Lock
with the the Java's built in syncronized
keyword effectively makes access to the lock already single threaded so it doesn't give the Lock
a chance to do any real work.Lock
should be done following the pattern below, this is outlined in the java docs of Locklock.readLock().lock();
try {
// Do work
} finally {
lock.readLock.unlock();
}