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.

  • 链接地址: http://www.djcxy.com/p/13268.html

    上一篇: null值为引发NullPointerException的日期

    下一篇: 为什么此代码不会抛出NullPointerException?