Spring 2002, CSE 428: Solution of MT 2

Exercise 1

  1. The string "Input error occurred. Please reenter :" is printed. Then the while loop is repeated, so the user has again the chance to enter a number.
  2. The string "Input error occurred. Please reenter :" is printed, but in this case the function readString() returns the last value of s (which is the empty string) and terminates, without giving again the user the chance to enter a number.
  3. In this case readString() rethrows the exception, and it will have to be handled by the caller, or rethrown again to the caller of the caller, etc.

Exercise 2

   class  Restaurant {
      
      private int tablesAvailable; // Number of tables available. 
                                   // Each table can accomodate 4 people.

      Restaurant(int totalNumerOfTables) { tablesAvailable = totalNumerOfTables; }

      public synchronized void enter(int numberOfTables) {
             if (tablesAvailable < numberOfTables) wait();
             tablesAvailable = tablesAvailable - numerOfTables;            
      }

      public synchronized void exit(int numerOfTables) {
             tablesAvailable = tablesAvailable + numerOfTables;
             notifyAll();  // here it is better to use notifyAll() instead than notify()
                           // because groups have different sizes: one may be able to enter, 
                           // and another not.
      }
   } 

   class Group extends Thread { 

      private int numberOfPeople; // Number of people composing the group.
      private Restaurant restaurant;

      Group(int n, Restaurant r) { numberOfPeople = n; restaurant = r; }

      public run() {
            < do some activity > 
            int numberOfTables = (numberOfPeople + 3)/4; // if numberOfPeople % 4 > 0 add one table
	    restaurant.enter(numberOfTables); // enter the restaurant
            < eat >
            restaurant.exit(numberOfTables); // exit the restaurant
            < do some other activity > 
      }

   }

Exercise 3

  1.    class Buffer {  // A one position buffer of Jobs.
           private Job content; 
           private boolean empty;
           
           public Buffer() { empty = true; }
      
           public synchronized void put(Job i) {
                while (!empty) wait();
                content = i;
                empty = false;  // notifyAll(); is not needed anymore
           }
      
           ... // same as before
    
           public synchronized Job get() { 
                if (empty) return null; // null will be the default value indicating insuccess
                empty = true;           // note the absence of a wait() statement. 
                notifyAll();
                return content;
           }
       }// end Buffer
    
    
       class JobsExercutor extends Thread { 
    
           private Buffer firstQueue; // first queue
           private Buffer secondQueue; // second queue;
    
           JobsExercutor(Buffer f, Buffer s) { firstQueue = f; secondQueue = s; }
    
           public run() {
               Job nextJob;
               while (true) {
                  nextJob = firstQueue.get();
                  if (nextJob != null)
    	          < execute nextJob > 
    	      nextJob = secondQueue.get();
                  if (nextJob != null)
    		  < execute nextJob >       
               }
          }
    
       }
    
    Note: several students have given a solution of the form
       class Buffer {  
           ...
           public synchronized boolean isEmpty() { return empty; }
           ...
           public synchronized Job get() {
                while (empty) wait();
                empty = true;
                notifyAll();
                return content;
           }
       }
    
       class JobsExercutor extends Thread { 
          ...
          public run() {
               Job nextJob;
               while (true) {
                  if (!firstQueue.isEmpty()){
    	          nextJob = firstQueue.get();
    		  < execute nextJob > 
    	      }
                  if (!secondQueue.isEmpty()){
    	          nextJob = secondQueue.get();
    		  < execute nextJob > 
    	      }
               }
          }
    
       }
    
    This solution is not completely correct wrt the specification: between the execution of the test !firstQueue.isEmpty() and the and the execution of the instruction nextJob = firstQueue.get(); another thread could empty the buffer, so the JobsExercutor could suspend forever on firstQueue (if noone puts jobs in firstQueue anymore) even if secondQueue is not empty.

  2. The JobsExercutor uses busy waiting. Unfortunately in Java we cannot suspend on the "or" of two conditions, that would be what we need here. Still we can avoid busy waiting by using a shared object of a new class, and by making the JobsExercutor suspend whenever both queues are empty, via a method calling a wait() instruction on the shared object. Naturally, the put action should then execute a method containing a notify() instruction on the shared object.

    Another solution would be to use two threads whose purpose is to take jobs from each queue, respectively, and feed them to the JobsExercutor.

Exercise 4

   import java.applet.*;
   import java.awt.*;
   import java.awt.event.*;

   public class HelloWorld extends Applet {
      
      private Choice choice;

      public void init ( ) {
         setBackground(Color.white);
	 addMouseListener(new MouseHandler());

	 choice = new Choice();
	 choice.addItem("Hello");
	 choice.addItem("World");
	 add(choice);
      }

	 private class MouseHandler extends MouseListener {
	    public void mouseClicked(MouseEvent e) {
	       Graphics g = new Graphics();
	       if (choice.getSelectedItem().equals("Hello") {
	          g.drawString("Hello", e.getX(), e.getY())
	       }
	       else g.drawString("World", e.getX(), e.getY())
	    }
         }
    }