Search code examples
javamultithreadingwaitnotify

Java: wait() and notify() confusion


I'm trying to implement a condition that only one thread to access: Let's say it's a bottle of water - I want only 1 person (thread) to be able to have it a time. Everything seems to work smoothly but I can't get the printing to be shown - the one before the call to wait(); .

public synchronized void getBotttle  {
    while(myCondition) {
      try {
        System.out.println("Printing that is never done?!");
        wait();
      }
      catch (InterruptedException e) {}
    }

    System.out.println("Printing that works");
    myCondition = true;
    notifyAll(); //or notify(), tried both

    try {
      Thread.sleep(time); // 
    }
    catch (InterruptedException e) {}
    System.out.println("Printing again");
    methodToMakeConditionFalse();
   // notifyAll(); even if I put it here its still the same
}

This method is called by the threads and it works as intended - only 1 thread has the "bottle" but the printing isn't there. Any ideas?


Solution

  • You don't have a complete example, which makes it hard to tell what you're doing wrong; my guess is that your condition flag isn't set appropriately. Here is a complete example which works, it makes sure that only one thread has access to a resource at a time.

    public class StuffExample {
    
        public static void main(String[] args) throws Exception {
         
            Worker worker = new Worker(new StuffHolder());
            Thread t1 = new Thread(worker); 
            Thread t2 = new Thread(worker); 
    
            t1.start();
            t2.start();
    
            Thread.sleep(10000L);
            t1.interrupt();
            t2.interrupt();
        }
    }
    
    class Worker implements Runnable {
        private StuffHolder holder;
    
        public Worker(StuffHolder holder) {
            this.holder = holder;
        }
    
        public void run() {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    holder.useStuff();
                    Thread.sleep(1000L);
                }
            }
            catch (InterruptedException e) {
            }
        }
    }
    
    class StuffHolder {
    
        private boolean inUse = false;
        private int count = 0;
        public synchronized void useStuff() throws InterruptedException {
            while (inUse) {
                wait();
            }
            inUse = true;
            System.out.println("doing whatever with stuff now, count=" 
                + count + ", thread=" + Thread.currentThread().getName());
            count += 1;
            inUse = false;
            notifyAll();
        }   
    }
    

    Output is:

    doing whatever with stuff now, count=0, threadid=Thread-0
    doing whatever with stuff now, count=1, threadid=Thread-1
    doing whatever with stuff now, count=2, threadid=Thread-0
    doing whatever with stuff now, count=3, threadid=Thread-1
    doing whatever with stuff now, count=4, threadid=Thread-0
    doing whatever with stuff now, count=5, threadid=Thread-1
    doing whatever with stuff now, count=6, threadid=Thread-0
    doing whatever with stuff now, count=7, threadid=Thread-1
    doing whatever with stuff now, count=8, threadid=Thread-0
    doing whatever with stuff now, count=9, threadid=Thread-1
    doing whatever with stuff now, count=10, threadid=Thread-0
    doing whatever with stuff now, count=11, threadid=Thread-1
    doing whatever with stuff now, count=12, threadid=Thread-0
    doing whatever with stuff now, count=13, threadid=Thread-1
    doing whatever with stuff now, count=14, threadid=Thread-0
    doing whatever with stuff now, count=15, threadid=Thread-1
    doing whatever with stuff now, count=16, threadid=Thread-1
    doing whatever with stuff now, count=17, threadid=Thread-0
    doing whatever with stuff now, count=18, threadid=Thread-1
    doing whatever with stuff now, count=19, threadid=Thread-0
    

    See Oracle's tutorial on guarded blocks.