0% found this document useful (0 votes)
12 views6 pages

Case Study IA2 OOC

Uploaded by

moh24amme
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views6 pages

Case Study IA2 OOC

Uploaded by

moh24amme
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

BMS INSTITUTE OF MANAGEMENT

DEPARTMENT OF CSE

OBJECT ORIENTED PROGRAMMING IN JAVA

CASE STUDY – IA2

14.5: Case Study- Cooperating Threads


For some applications it is necessary to synchronize and coordinate the behavior of threads to
enable them to carry out a cooperative task. Many cooperative applications are based on
the producer/consumer model. According to this model, two threads cooperate at producing and
consuming a particular resource or piece of data. The producer thread creates some message or
result, and the consumer thread reads or uses the result. The consumer has to wait for a result to
be produced, and the producer has to take care not to overwrite a result that hasn’t yet been
consumed. Many types of coordination problems fit the producer/consumer model.

One example of an application for this model would be to control the display of data that is read
by your browser. As information arrives from the Internet, it is written to a buffer by the producer
thread. A separate consumer thread reads information from the buffer and displays it in your
browser window. Obviously, the two threads must be carefully synchronized.

Problem Statement

To illustrate how to address the sorts of problems that can arise when you try to synchronize
threads, let’s consider a simple application in which several threads use a shared resource. You’re
familiar with those take-a-number devices that are used in bakeries to manage a waiting line.
Customers take a number when they arrive, and the clerk announces who’s next by looking at the
device. As customers are called, the clerk increments the “next customer” counter by one.

Our task is to build a multithreaded simulation that uses a model of a take-a-number device to
coordinate the behavior of customers and a (single) clerk in a bakery waiting line. To help illustrate
the various issues involved in trying to coordinate threads, we will develop more than one version
of the program.

Problem Decomposition

This simulation will use four classes of objects.

Bakery—creates the threads and starts the


TakeANumber—represents the gadget that keeps track of the next customer to be served.

Clerk—uses the TakeANumber to determine the next customer and will serve the customer.

Customer—represents the customers who will use the TakeANumber to take their place in
line.

Design: The TakeANumber Class

The TakeANumber class must track two things: Which customer will be served next, and which
waiting number the next customer will be given. This suggests that it should have at least two
public methods: nextNumber(), which will be used by customers to get their waiting numbers,
and nextCustomer(), which will be used by the clerk to determine who should be served (Fig.
14.18). Each of these methods will simply retrieve the values of the instance

variables, next and serving, which keep track of these two values. As part of the object’s state,
these variables should be private.

How should we make this TakeANumber object accessible to all of the other objects—that is, to
all of the customers and to the clerk? The easiest way to do that is to have the main program pass
a reference to the TakeANumber when it constructs the Customers and the Clerk. They can each
store the reference as an instance variable. In this way, all the objects in the simulation can share
a TakeANumber object as a common resource. Our design considerations lead to the definition of
the TakeANumber class shown in Figure [fig-takeanumber1].

class TakeANumber {
private int next = 0; // Next place in line
private int serving = 0; // Next customer to serve

public synchronized int nextNumber() {


next = next + 1;
return next;
} // nextNumber()

public int nextCustomer() {


++serving;
return serving;
} // nextCustomer()

} // TakeANumber

Note that the nextNumber() method is declared synchronized. As we will discuss in more detail,
this ensures that only one customer at a time can take a number. Once a thread begins executing
a synchronized method, no other thread can execute that method until the first thread finishes.
This is important because, otherwise, several Customers could call the nextNumber method at
the same time. It’s important that the customer threads have access only one at a time, also
called mutually exclusive access to the TakeANumber object. This form of mutual exclusion is
important for the correctness of the simulation.

What is the analogue to mutual exclusion in the real-world bakery situation?

The Customer Class

A Customer thread should model the behavior of taking a number from


the TakeANumber gadget. For the sake of this simulation, let’s suppose that after taking a
number, the Customer object just prints it out. This will serve as a simple model of “waiting on
line.” What about the Customer’s state? To help distinguish one customer

from another, let’s give each customer a unique ID number starting at 10001, which will be set in
the constructor method. Also, as we noted earlier, each Customer needs a reference to
the TakeANumber object, which is passed as a constructor parameter . Note that before taking a
number the customer sleeps for a random interval of up to 1,000 milliseconds. This will
introduce a bit of randomness into the simulation.

public class Customer extends Thread {

private static int number = 10000; // Initial ID number


private int id;
private TakeANumber takeANumber;

public Customer( TakeANumber gadget ) {


id = ++number;
takeANumber = gadget;
}

public void run() {


try {
sleep( (int)(Math.random() * 1000 ) );
System.out.println("Customer " + id +
" takes ticket " + takeANumber.nextNumber());
} catch (InterruptedException e) {
System.out.println("Exception " + e.getMessage());
}
} // run()
} // Customer
Another important feature of this definition is the use of the static variable number to assign each
customer a unique ID number. Remember that a static variable belongs to the class itself, not to
its instances. Therefore, each Customer that is created can share this variable. By incrementing it
and assigning its new value as the Customer’s ID, we guarantee that each customer has a unique
ID number.

The Clerk Class

The Clerk thread should simulate the behavior of serving the next customer in line, so
the Clerk thread will repeatedly access TakeANumber.nextCustomer() and then serve that
customer. For the sake of this simulation, we’ll just print a message to indicate which customer is
being served. Because there’s only one clerk in this simulation, the only variable in its internal
state will be a reference to the TakeANumber object (Fig. 14.22). In addition to the constructor,
all we really need to define for this class is the run() method. This

leads to the definition of Clerk shown in Figure [fig-clerk1]. In this case, the sleep() method is
necessary to allow the Customer threads to run. The Clerk will sit in an infinite loop serving the
next customer on each iteration.

public class Clerk extends Thread {


private TakeANumber takeANumber;

public Clerk(TakeANumber gadget) {


takeANumber = gadget;
}

public void run() {


while (true) {
try {
sleep( (int)(Math.random() * 50));
System.out.println("Clerk serving ticket " +
takeANumber.nextCustomer());
} catch (InterruptedException e) {
System.out.println("Exception " + e.getMessage() );
}
} //while
} //run()
} // Clerk

The Bakery Class

Finally, Bakery is the simplest class to design. It contains the main() method, which gets the
whole simulation started. As we said, its role will be to create one Clerk thread and
several Customer threads, and get them all started (Fig. [fig-bakery]). Notice that the Customers
and the Clerk are each passed a reference to the shared TakeANumber gadget.

-2pc

public class Bakery {


public static void main(String args[]) {
System.out.println("Starting clerk and customer threads");
TakeANumber numberGadget = new TakeANumber();
Clerk clerk = new Clerk(numberGadget);
clerk.start();
for (int k = 0; k < 5; k++) {
Customer customer = new Customer(numberGadget);
customer.start();
}
} // main()
} // Bakery

Problem: Nonexistent Customers

Now that we have designed and implemented the classes, let’s run several experiments to test
that everything works as intended. Except for the synchronized nextNumber() method, we’ve
made little attempt to make sure that the Customer and Clerk threads will work together
cooperatively, without violating the real-world constraints that should be satisfied by the
simulation. If we run the simulation as it is presently coded, it will generate five customers and
the clerk will serve all of them. But we get something like the following output:

Starting clerk and customer threads


Clerk serving ticket 1
Clerk serving ticket 2
Clerk serving ticket 3
Clerk serving ticket 4
Clerk serving ticket 5
Customer 10004 takes ticket 1
Customer 10002 takes ticket 2
Clerk serving ticket 6
Customer 10005 takes ticket 3
Clerk serving ticket 7
Clerk serving ticket 8
Clerk serving ticket 9
Clerk serving ticket 10
Customer 10001 takes ticket 4
Customer 10003 takes ticket 5

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy