4

I have one thread1:

if(object != null){
   object.play();
}

and another thread2 that can write null into object reference at any time.

I will run these threads at same time. I know thread2 can rewrite object reference after the null check and that will throw NullPointerException. Is it possible for thread2 to rewrite object reference after NullPointerException check?

6
  • Perhaps use a boolean flag to indicate to the other thread that it's null? Commented Oct 8, 2012 at 12:34
  • You mean, between dereferencing object and calling play()? Absolutely. The rule of thumb is that without proper barriers and synchronisation, absolutely anything can happen. That's obviously not literally true but it often helps if you approach it that way. Commented Oct 8, 2012 at 12:34
  • What's the difference between "null check" and "NullPointerException check" ? Commented Oct 8, 2012 at 12:35
  • 3
    Perhaps you may want to read up on the synchronized keyword. Commented Oct 8, 2012 at 12:36
  • 3
    @Redandwhite I dare you to put that as an answer! Commented Oct 8, 2012 at 12:42

7 Answers 7

6

Is it possible to for thread2 to rewrite object reference after NullPointerException check ?

Absolutely - it could change the value of object while the play() method is executing, if that's what you mean. That wouldn't cause an error in itself.

Note that without synchronization or other memory barriers, thread2 could change the value of object without thread1 noticing for an indeterminate period of time.

It's hard to say what you ought to do, without any other knowledge of the bigger aim of the code.

Sign up to request clarification or add additional context in comments.

2 Comments

Well, I dind't have anything specific when I wrote it, It was just a thought. What do you mean by 'That wouldn't cause an error in itself.' ? I would not cause NullPointerException or any error ? Thank you for your answer.
@jellyfication: It won't cause a NullPointerException after the initial check. The value of object is evaluated, and that determines whether a NullPointerException is thrown, and the target of the call. Changes to object won't affect which target is used.
5

Simple synchronized example:

/**
To maintain thread safety, only access this through getter and setter
or other synchronized method
**/
private ObjectType object;

public synchronized void setObject(ObjectType object) {
  this.object = object;
}

public synchronized ObjectType getObject() {
  return object;
}

public void doPlay() {
  final ObjectType obj = getObject();
  //here, thread 2 can change "object", but it's not going to affect this thread
  //as we already safely got our reference to "object" in "obj".
  if(obj != null){ 
   obj.play(); 
  }
}

public synchronized void alterativeDoPlay() {
  //the difference here is that another thread won't be able to change "object"
  //until the object's play() method has completed.
  //depending on the code in play, this has potential for deadlocks, where as
  //the other `doPlay` has zero deadlock potential.
  if(object != null){
   object.play(); 
  }
}

Comments

1

If object is an instance variable or a static variable that can be changed from multiple threads, its value can change between the time you test it in the if statement and the time when you call its instance method.

You can modify the code to avoid this problem by copying the object into a local variable, like this:

Playable objectCopy = object;
if(objectCopy != null) {
    objectCopy.play();
}

Since objectCopy is a local variable, its value cannot change between the test and the call of play. Of course the state of the playable object itself can change, but that is not something that can be fixed by null checking.

6 Comments

This does not alone make it threadsafe. object would need to be marked as volatile
Don't disagree will solve NPE, but is my understanding that without volatile (or other synchronization preferrable) thread 1 could be looking at cached value for object, so changes made by thread 2 may not be seen. So that's not going to be result OP is looking for/expecting.
@weston Absolutely! Without synchronization, this exercise will be full of unexpected results (unexpected in a bad way, of course).
Playable objectCopy = object; does not create a new object...now you just have another reference to the same object, and have achieved nothing.
@lynks Of course I achieved something! My newly created reference to the same object is local, and is therefore immune to possible changes of the original reference. This makes my code fragment free of possible null pointer exceptions - quite a departure from the OP's code!
|
1

You can use CountDownLatch here. Where Thread1 will wait to count down by Thread2 and you can perform the task in thread2 and stop count down.

Code snippet -

CountDownLatch latch = new CountDownLatch(1);
new Thread1(latch).start();
new Thread2(latch).start();
public class Thread1 extends Thread {
  private final CountDownLatch startLatch;

  public Thread1(CountDownLatch startLatch) {
    this.startLatch = startLatch;
  }
  public void run() {
    try {
      startLatch.await();
      // ... perform task
    } catch (InterruptedException iex) {}
  }
}

public class Thread1 extends Thread {
  private final CountDownLatch stopLatch;

  public Thread1(CountDownLatch stopLatch) {
    this.stopLatch = stopLatch;
  }
  public void run() {
    try {
      // perform task
    } finally {
      stopLatch.countDown();
    }
  }
}

Comments

1

According to Brian's Law :

When we write a variable, which next has to be read by another thread, or when we are reading a variable which has lately been written by another thread, then use synchronization. Synchronize the atomic statements or getter/setters which has access to the crucial state of data with the same monitor lock.

- Use synchronization.

- You can use CountDownLatch from java.util.concurrent

Comments

0

You will need to use some form of synchronisation primitive to solve this problem. See "Syncrhonised Statements" here. In your case you will need to wrap the whole if block and any places in any threads that use or update object2.

Comments

0

As my professor said: "Concurrency is a pretty unstable guy. We never know what to expect of him." Comming to your question:

Is it possible for thread2 to rewrite object reference after NullPointerException check?

Yes

Thread2 can access the object many times during 1 occurrence of thread1. Or the other way around. There may be many occurrences of thread1, while thread2 accesses the object.

If you use simple

System.out.println();

in many places in your code, you may notice the output in the console to be displayed AFTER the NullPointerException error(if it wasn't caught).

2 Comments

"Concurrency is a pretty unstable guy. We never know what to excpect of him." - That is true in the general sense. But the flip side is that if you pay attention to the details, you can write concurrent code that is 100% reliable and predictable.
@StephenC Later on the guy introduced his wife Synchronization ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.