Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 (i.e., 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?

like image 979
Dave Jarvis Avatar asked Nov 02 '13 00:11

Dave Jarvis


People also ask

How do you throw NullPointerException?

NullPointerException is thrown when a reference variable is accessed (or de-referenced) and is not pointing to any object. This error can be resolved by using a try-catch block or an if-else condition to check if a reference variable is null before dereferencing it.

When should we throw a NullPointerException?

NullPointerException is thrown when program attempts to use an object reference that has the null value. These can be: Invoking a method from a null object. Accessing or modifying a null object's field.

Why NullPointerException should not be caught?

It is generally a bad practice to catch NullPointerException. Programmers typically catch NullPointerException under three circumstances: The program contains a null pointer dereference. Catching the resulting exception was easier than fixing the underlying problem.

What is NullPointerException in Java example?

NullPointerException is a runtime exception and it is thrown when the application try to use an object reference which has a null value. For example, using a method on a null reference.


1 Answers

Two things:

  1. 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.

  2. 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.

like image 164
James Avatar answered Oct 03 '22 16:10

James