I was asked the following question on an interview. Given the following code, if methods add
and doAction
are being invoked by multiple threads, how can we get a NullPointerException
when printing toString
?**
public class Test{
private List<Object> obj = new ArrayList<Object>();
public void add(Object o){
obj.add(o);
}
public void doAction(){
for(Object o: obj){
System.out.println(o.toString()); // maybe NPE, why?
}
}
}
Cut out all other multithread concerns.
First, let's change the name of the variable; List<Object> list=new ArrayList<>();
because "obj" is a really awful name for a variable that refers to a List
.
OK, When the program calls list.add(o);
, it may need to grow the array. That means it's got to:
null
, andIf thread A is doing that while at the same time thread B is calling iterator.next()
, thread B could end up reading a null
value from the new array even after thread A has already copied an object reference into that member of the array.
Remember: When threads access memory with no synchronization, then it is possible for a reader thread to see updates to variables/fields/array members happen in a different order from the program order in which the writing thread actually performed them.
Test t = new Test();
t.add(null);
t.doAction(); //NPE triggered
No nullability guarentees on the obj
list, so it might contain null values.
Regarding the problem with multithreading refers to the ConcurrentModificationException
since the "for-all" look uses an Iterator
internally. If an element is added while iterating it will cause an exception to be thrown.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With