Title: Solution to practical exercise 2
1Solution topractical exercise 2
- Thread synchronization in Java
- The Producer/Consumer model
- The Barbershop example
2The exercise
- Your task was to implement a version of the
Barbershop example - A doorman produces customers.
- Customers are buffered in a ring of chairs.
- Three barbers consume customers.
- A handed-out GUI visualizes the proceedings.
3Key points
- The buffer of chairs is implemented by the
CustomerQueue class. - This class serves as a monitor.
- The Barber and Doorman classes implement the
Runnable interface, and have run() methods
consuming and producing customers, respectively.
4The run() methods
- The Doorman repeatedly creates new customers and
inserts them into the CustomerQueue - public void run ()
- while(!stopRunning)
- // Sleep a random period, then add a new
customer - try
- Thread.sleep(
- (long)(Math.random()Globals.doormanSleep)
) - catch (InterruptedException e)
- customerQueue.addCustomer(new Customer())
-
-
5The run() methods
- The Barber repeatedly removes customers from the
CustomerQueue - public void run()
- while(!stopRunning)
- // Sleep a random period
- try
- gui.barberIsSleeping(myPosition)
- Thread.sleep((long)(Math.random()Globals.ba
rberSleep)) - gui.barberIsAwake(myPosition)
- catch (InterruptedException e)
- // Serve a new customer
- Customer c customerQueue.removeCustomer(myPo
sition) - serveCustomer(c)
-
-
- The stopRunning variable is set to true by the
stopThread() method and is used to end the thread
in a safe way.
6The buffer
- The customer buffer is implemented by the
CustomerQueue class and takes care of thread
synchronization. - The CustomerQueue class encapsulates a data
structure with three variables that must be
protected by a monitor - / The circular buffer of customers /
- private Customer buffer
- / The current position of the first customer in
the queue / - private int head
- / The current pos. of the first free place in
the queue / - private int tail
- If operations on these variables are not mutually
exclusive, data inconsistencies can easily occur.
7Adding customers
- The addCustomer() method adds a customer to the
buffer, - but must wait if the buffer is full.
- public synchronized void addCustomer(Customer c)
- while(currentLength gt maxLength)
- gui.println("Doorman is waiting for free
chairs...") - try
- wait()
- catch (InterruptedException e)
- gui.println("Doorman was notified of a free
chair.") -
- // Add the customer at the tail of the queue
- buffertail c
- // Update the GUI
- gui.fillLoungeChair(tail, c)
- // Update the queue parameters
- tail (tail1)maxLength
- currentLength
- // If the queue was empty, notify all the
barbers
8Removing customers
- The removeCustomer() method removes a customer
from the buffer, - but must wait if the buffer is empty.
- public synchronized Customer removeCustomer(int
barberNo) - while(currentLength 0)
- gui.println("Barber "barberNo" is waiting
for customers...") - try
- wait()
- catch (InterruptedException e)
- gui.println("Barber "barberNo" was
notified of a new customer.") -
- // Fetch the customer at the head of the queue
- Customer c bufferhead
- // Update the GUI
- gui.emptyLoungeChair(head)
- // Update the queue parameters
- head (head1)maxLength
- currentLength--
- // If the queue was full, notify the doorman
that there's a free chair
9The message flow
- When a doorman invokes addCustomer(), and the
buffer was empty, he notifies all barbers that
are waiting for customers that a customer has
been added.
public synchronized void addCustomer(Customer
c) // If the queue was empty, notify
// all the barbers that a customer // has
arrived if(currentLength 1)
notifyAll()
public synchronized Customer
removeCustomer() while(currentLength 0)
try wait()
catch(InterruptedException e)
10The message flow
- When a barber invokes removeCustomer(), and the
buffer was full, he notifies the doorman that
there is room for more customers.
public synchronized Customer
removeCustomer() // If the queue was
full, notify //the doorman that there's a
//free chair if (currentLength
(maxLength-1)) notifyAll() return c
public synchronized void addCustomer(Customer
c) while(currentLengthgt maxLength)
try wait() catch(InterruptedExce
ption e)
11Synchronization logic
- Note that a notifyAll() call will wake up all
waiting threads, also threads who are waiting at
the wrong place. - It is up to the programmer to ensure that threads
wait at the right place. - In this case, the buffer cannot be both empty and
full, so there cannot be threads waiting in the
removeCustomer() and addCustomer() methods
simultaneously. - If these kinds of guarantees cant be made, each
pair of wait() and notify() invocations must use
separate monitors.
12Questions?