Why does this code not throw a NullPointerException?
Background
I would like to understand why a snippet of code does not throw a NullPointerException.
Source Code
Consider the following code:
public class Agent {
public List files = new ArrayList();
public void deliver() {
if( files != null && files.iterator().hasNext() ) {
File file = (File)files.iterator().next();
}
files = new ArrayList();
}
}
The deliver
method is called repeatedly, whilst the following code runs in a separate thread:
public void run() {
agent.files = null;
}
There is only a single agent
instance.
Problem
A NullPointerException is never thrown.
However, when the deliver
method pauses, even for 0 milliseconds, a NullPointerException is thrown as expected:
public void deliver() {
if( files != null ) {
Thread.currentThread().sleep( 0 );
if( files.iterator().hasNext() ) {
File file = (File)files.iterator().next();
}
}
files = new ArrayList();
}
My understanding was that there is, in theory, a race condition between checking for files == null
and calling files.iterator().hasNext()
. In practice, I cannot trigger the race condition without introducing the pause (ie, splitting the null check from the subsequent method call).
Question
Why does the first deliver
method not throw an exception when the null check and usage are combined in the same statement?
Two things:
Thread.sleep(0) still halts execution (potentially more than 0 milliseconds). Basically, even a 0 sleep causes execution on that thread to halt briefly, and then restart. This gives the other thread a chance to run and finish, which is why you're able to trigger the race condition.
files should be volatile
, otherwise the JVM is permitted to optimize in such a way that you may never notice that it's changing value, because it doesn't think it needs to maintain consistency between the threads.