0

I encountered following code in my java book.I think while loop is useless, the program will not run the while loop because of the valueSet.I debug these code step by step it did not enter while loops.

Why we type these while loops?

get() while

 while(!valueSet)
         try {
         wait();
         } catch(InterruptedException e) {
         System.out.println("InterruptedException caught");
         }

put while:

while (valueSet)
       try {
        wait();
       } catch (InterruptedException e) {
        System.out.println("InterruptedException caught");
       }

[Short explanation:Q, the queue that trying to synchronize; Producer, the threaded object that is producing queue entries; Consumer, the threaded object that is consuming queue entries]

Full code:

class Q {
 int n;
 boolean valueSet = false;    
 synchronized int get() {
  while (!valueSet)
   try {
    wait();
   } catch (InterruptedException e) {
    System.out.println("InterruptedException caught");
   }
  System.out.println("Got: " + n);
  valueSet = false;
  notify();
  return n;
 }


 synchronized void put(int n) {

  while (valueSet)
   try {
    wait();
   } catch (InterruptedException e) {
    System.out.println("InterruptedException caught");
   }

  this.n = n;
  valueSet = true;
  System.out.println("Put: " + n);
  notify();
 }
}
class Producer implements Runnable {
 Q q;
 Producer(Q q) {
  this.q = q;
  new Thread(this, "Producer").start();
 }
 public void run() {
  int i = 0;
  while (true) {
   q.put(i++);
  }
 }
}
class Consumer implements Runnable {
 Q q;
 Consumer(Q q) {
  this.q = q;
  new Thread(this, "Consumer").start();
 }
 public void run() {
  while (true) {
   q.get();
  }
 }
}
public class Test {
 public static void main(String args[]) {
  Q q = new Q();
  new Producer(q);
  new Consumer(q);
  System.out.println("Press Control-C to stop.");
 }
}
my-lord
  • 2,453
  • 3
  • 12
  • 26

1 Answers1

0

Why we type these while loops?

When you use thread communication with notify() and wait(), you normally wait until certain condition is met. The usual template that is used is something similar to:

synchronized(lock){
    while(!condition){
        lock.wait();
    }
}

When calling wait() you should always check for a condition because the thread can be wake for no reason (spurious wake-up), for interruption, notifications, and others reasons listed here.

You need the sincronized block or a synchronized method to be able to call wait(), because you have to own the monitor.

When other thread calls the notify() or notifyAll() (usually also changing the condition value) the thread that is waiting (competes if necessary) and eventually acquires the lock and continue the execution, which means the condition of the while is checked again, in case is met then continues the execution, otherwise it waits again.

In this case both loops are reached and are necessary, the variable valueSet is initialized in false so the producer [while (valueSet)] is the only one with a free pass (it doesn't wait the first time) and it makes sence since it is the producer. The consumer only passes the loop [while (!valueSet)] when the consumer already produce and change the value of the condition. The producer cannot produce another value while the consumer hasn't consume the current.

After the first produce/consume communication, the main loop in both [while (true)] repeats again the cycle produce/consume, so the threads are always synchronized; if the consumer starts first, waits until the value is produced, if the producer starts and the consumer still has a pending value, it waits until it is consumed.

Community
  • 1
  • 1
Jose Da Silva Gomes
  • 3,814
  • 3
  • 24
  • 34