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 > } }
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.
Another solution would be to use two threads whose purpose is to take jobs from each queue, respectively, and feed them to the JobsExercutor.
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()) } } }