1

I am trying to get my Producer/Consumer working and I deliberately don't want to use BlockingQueue to understand finer details here. I understand when I call object.wait() the thread looses its lock and goes to WAITING state till someone notifies (notify/notifyAll) which beings it back to BLOCKED state and this thread would go to RUNNABLE if it acquires the lock.

    private class Consumer implements Runnable{
        private final MyQueue<Integer> queue;
        public Consumer(MyQueue<Integer> queue){
            this.queue = queue;
        }
        @Override
        public void run(){
            while(true){
                synchronized (queue) {
                    //Block till new available
                    while(queue.isEmpty()){
                        try {
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //Consume
                    queue.dequeue();
                    queue.notifyAll(); //Notify people waiting on queue full condition
                }
            }
        }
    }

My question is it possible that (with respect to code above):

  1. My thread was waiting and woke up after wait (some one notified) and i got the lock
  2. I made a check queue.isEmpty() and it was not empty and execution goes to next line
  3. Just before the next line queue.dequeue() is executed CPU context switched my thread.
  4. Next when i get my cpu slice and lock, i run queue.dequeue() and say queue is empty

I know a usual CPU scheduler gives a quantum of time to each thread to avoid the context switching costs.

Mat
  • 202,337
  • 40
  • 393
  • 406
Monish
  • 13
  • 4

1 Answers1

1

That situation won't happen, precisely because any modification to the queue is (or at least should be) done from a synchronized block on the queue. So, no other thread can modify the queue between then end of the while loop and the call to dequeue(), since your thread is the one holding the lock.

Of course, if some other consumer also removes elements from the queue without synchronizing on the queue, you will have this problem. But that would simply be a bug in your code. Using encapsulation is the best way to avoid those kinds of bugs. If you used a BlockingQueue, the BlockingQueue class would encapsulate the exclusive access to the shared state, and you wouldn't have to make sure every access to the queue is properly synchronized, since the BlockingQueue would do it for you.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Does a thread that context switches holds the lock and goes out of execution? – Monish Oct 19 '14 at 13:45
  • The thread keeps the lock until it leaves the synchronized block. Whether the thread is currently executing or not doesn't change anything. If the scheduler decides to switch to other threads right after the while loop and before the call to dequeue, all the other threads waiting for the lock will keep being blocked until the thread holding the lock is rescheduled, and continues executing until it leaves the synchronized block. – JB Nizet Oct 19 '14 at 13:50
  • Thanks! that makes it very clear "The thread keeps the lock until it leaves the synchronized block. Whether the thread is currently executing or not doesn't change anything". Although its interesting that when OS context switches it may slow down threads which are waiting for lock – Monish Oct 19 '14 at 13:59