I need help in understanding the below code :
private Predicate composedPredicate = null;
public boolean evaluate(Task taskData) {
boolean isReadLock = false;
try{
rwl.readLock().lock();
isReadLock = true;
if (composedPredicate == null) {
rwl.readLock().unlock();
isReadLock = false;
rwl.writeLock().lock();
if (composedPredicate == null) {
//write to the "composedPredicate" object
}
}
}finally {
if (isReadLock) {
rwl.readLock().unlock();
}else{
rwl.writeLock().unlock();
}
}
return composedPredicate.test(taskData);
}
What will happen if we don't use Read Locks in the above code? Like :
public boolean evaluate(Task taskData) {
//boolean isReadLock = false;
try{
//rwl.readLock().lock();
//isReadLock = true;
if (composedPredicate == null) {
//rwl.readLock().unlock();
//isReadLock = false;
rwl.writeLock().lock();
if (composedPredicate == null) {
//write to the "composedPredicate" object
}
}
}finally {
rwl.writeLock().unlock();
}
return composedPredicate.test(taskData);
}
The first code that you posted is a correct implementation of the double-checked locking approach in Java using a read/write lock.
Your second implementation without a read-lock is broken. The memory model allows writes to be reordering from the perspective of another thread seeing the result of the writes to memory.
What could happen is that you could be using a not-fully initialized instance of Predicate in the thread that is reading it.
Example with your code:
We have thread A and B both running evaluate
and composedPredicate is null
initially.
composedPredicate
is null
Predicate
composedPredicate
composedPredicate
is not null
composedPredicate.test(taskData);
composedPredicate.test(taskData);
is run using a not-fully initialized instance and your code has random unexpected errors in production resulting in great losses to your company (potentially that happens .. depends on the system that you're building)Whether or not the reordering of step 4 and 5 happens depends on many factors. Maybe it only does under heavy system load. It may not happen at all on your OS, hardware, version of JVM, etc. (But on the next version of the JVM, your OS, or when you move your application to a different physical machine, it may suddenly start happening)
Bad idea.