12

I'm making a program with while loops that execute in this manner:

  1. Main thread enters a while loop.
  2. Nothing happens in the while loop.
  3. Thread will stay in the while loop until the condition is satisfied.
  4. Another thread runs a function that will satisfy said condition.

Here is an example:

while(path != null);

There's another function in the class that will set the path to null, and once that happens the main thread should exit this loop. The other function is called in another thread.

However, the main thread does not exit the loop even when path is set to null. Any suggestions?

CODE:

try 
 { 
  for (Node n:realpath) 
    { 
      Thread.sleep(100); 
      actor.walk(n); 
     }
    Thread.sleep(100); 
 } 
 catch (InterruptedException ex) 
  { 
    Logger.getLogger(VNScreen.class.getName()).log(Level.SEVERE, null, ex); 
  } 
  realpath.clear(); 
  path = null;

if(path == null)
    System.out.println("NULLED PATH");
6
  • 2
    Where is path defined? It may need to be volatile. Commented Dec 7, 2011 at 2:17
  • 2
    if you post your full code, people will be more able to find your problem. Commented Dec 7, 2011 at 2:18
  • path is a private property in the class. Both functions above are also in said class. Commented Dec 7, 2011 at 2:20
  • Someone took care of it for you, @AbrahamMiguelEspiritu, but in the future it is better to edit your original question to add code. It's far more readable. Commented Dec 7, 2011 at 2:29
  • Prove that path is set to null by logging it. I am not convinced that Thread executes. Commented Dec 7, 2011 at 2:35

4 Answers 4

13

Busy waits are very expensive. I'd do it this way:

Object LOCK = new Object(); // just something to lock on

synchronized (LOCK) {
    while (path != null) {
        try { LOCK.wait(); }
        catch (InterruptedException e) {
            // treat interrupt as exit request
            break;
        }
    }
}

Then when you set path to null, just call

synchronized (LOCK) {
    LOCK.notifyAll();
}

(You can just synchronize on this if both pieces of code are in the same object.)

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

2 Comments

Thank you so much, do you think where this lock variable should be, in class that calls wait or in class that notifyAll?
@HalilİbrahimOymacı - I don't think it matters, as long as the variable is accessible to all code that needs it. It could even be a separate singleton object in its own class.
6

Rather than using a low level wait/notify approach, and to avoid busy waiting with a volatile, you can use a CountDownLatch. Because there is only one event to expect, instantiate the latch as:

CountDownLatch latch = new CountDownLatch(1);

Replace your while (path != null) with:

latch.await();

and in your main code, simply do:

path = somePath;
latch.countDown();

Comments

4

You probably need to declare path to be volatile. If the variable is not declared to be volatile then the compiler is free to cache its value in a register, and so any change to the value will not be recognized.

But in general this style of code is very bad (except in some low-level real-mode stuff). While your while loop is looping it's consuming 100% of the CPU, so whatever other process there is to change the value of path may never get cycles to execute, and other processes that do mundane things like maintain communications links or update the mouse cursor location will not execute either.

Best is to do some sort of event/message/semaphore based communications, so that your "loop" waits for a signal before continuing. "Acceptable" is to utilize some sort of delay, such as Thread.sleep, so that you only "poll" the variable every few milliseconds, say. You could also try Thread.yield, but that's sort of a crap-shoot and would not produce reliable results across a range of environments.

Comments

-1

the main thread does not exit the loop because because in while condition does not anything and checking condition is doing very speedy and while not sense changing variable. you have 2 way for resolve this problem: 1-in while loop waiting for a short time for example 5ms

    while(path != null){
     try{
       Thread.currentThread().sleep(50);
     }catch(){
       //do nothing
     }
    }

2-define path variable as volatile:

  volatile String path;

1 Comment

The Java memory model gives no guarantee whatsoever that your first solution will work. It is even likely that it won't work if you run it with a -server argument because the condition will be optimised away and transformed in to while(true).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.