CS 537 - Spring 2004
Assignment 2: Precious Metals

Due Wednesday, Feb 25 at 1:00 am.
Note: There is a Frequently Asked Questions (FAQ) page for this project. It should be considered an integral part of the specifications. Check it from time to time, since new items may be added.1

Errata: The example in the Introduction should read

Introduction

International Buillion and Metals corporation (IBM) is the worlds largest trading company in precious metals. They have contracted with you for a new trading system written in Java. For this assignment, you will write a pilot system that handles just three metals: Gold, Platinum, and Uranium. IBM brokers get metals from refiners and supply them to consumers. The refiners will be represented in your program by a single Java thread that periodically delivers shipments of refined metals to the brokers. The brokers are represented by three monitors, one for each metal. There may be any number of Consumer threads.

Each broker maintains a stock of all three metals, but is a "supplier" for only one of them, called its "specialty." From time to time, the refiner delivers a shipment of refined metal to the broker who is the supplier for it. For example, the refiner might deliver 30 ounces of gold to the gold supplier. Consumers periodically place purchase orders with brokers. Each order specifies the number of ounces of each metal. It can be placed with any broker. A broker will fill the order from its own stock if possible. If the supplier for metal M cannot fill an order because it does not have enough of M on hand, it just waits until it gets more from the refiner, but if it is short some other metal, it attempts to get it by trading with the supplier for that metal. To keep things simple, we will assume, somewhat unrealistically, that ounces of gold, platinum, or uranium are all equally valuable. That is, three ounces of gold can be swapped for three ounces of uranium or three ounces of platinum.

For example, suppose a consumer places an order with the gold broker for 4 ounces of gold and 1 ounce of platinum.

A broker treats a request from another broker just like an order from a consumer. If it can fill it immediately, it will. Otherwise, since the request must be for its specialty metal, it will just wait until it gets more from the refiner.

Implementing the System in Java

We have supplied three classes, Project2, Refiner, and Consumer, and two interfaces, IBM and Broker. The classes Refiner and Consumer are meant to be used as threads (that is, they implement Runnable). You are expected to write a class BrokerImplementation that implements Broker. BrokerImplementation is a "monitor" class, meaning that a broker does not act on its own, only in response to a call from a refiner or consumer. Project2 is the main class. It creates one refiner thread and some number (specified on the command line) of consumer threads and starts them running.

From time to time the refiner thread delivers a load of some metal to the supplier of that metal by calling the Broker method


    public void deliver(int ounces);
From time to time a consumer places an order by contacting a random broker and calling the Broker method

    public void get(int[] order);
The array order contains one non-negative integer for each metal, indicating how much of that metal is desired. For example, to get three ounces of gold and one ounce of uranium, a consumer might use code like this:2

    int[] order = new int[METALS];
    order[GOLD] = 3;
    order[URANIUM] = 1;
    int whichBroker = Project2.randInt(METALS);
    Project2.specialist(whichBroker).get(order);
As you can see, the class Project2 provides several handy utilities as static methods. We will explain these in more detail below.

A broker who does not have enough of a metal on hand to satisfy a request may try to get more from the supplier of that metal by calling the method


    public void swap(int what, int ounces);
This method indicates that the calling broker is willing to swap ounces ounces of metal what for ounces ounces of the supplier's specialty. For example, the call

    Project2 . speciality(GOLD) . swap(PLATINUM, 2);
indicates that the caller is willing to swap 2 ounces of platinum for two ounces of gold. After the call returns (calls to get and swap never fail, but they may delay the caller for a while), the caller should subtract 2 from its supply of platinum and add 2 to its supply of gold.

When a broker cannot satisfy a get or swap request because it does not have enough of the metal in which it specializes, it blocks the caller (using the Java wait method) until it can. A broker that is blocked waiting for something should continue to accept calls from other consumers or brokers.

Your solution must be deadlock-free, but it does not have to be "fair". In particular, you do not have to prevent starvation (an unlucky consumer who repeatedly gets passed over).

Details

Grab copies of all six .java files form ~cs537-2/public/html/source/p2:

    mkdir project2
    cd project2
    cp ~cs537-2/public/html/source/p2/*.java .
Read the documenatation online.

WARNING: These classes may need to be updated from time to time. Check the Frequently Asked Questions (FAQ) frequently to see if you need to fetch a fresh copy.

GetOpt.java (documentation)

This is a handy class for parsing command-line options. It is used by Project2.main() so you need copies of it, but you do not need to read or understand it (but you can if you like).

Project2.java (documentation)

This is the main program. It accepts two command line arguments: the number of consumers and the number of iterations executed by the refiner before it terminates. There are also two optional command-line flags
-v
Request verbose debugging (see setVerbose).
-r
Use the same random seed each time the program is run. This will cut down the amount of variability from run to run and may be helpful in reproducing errors.

In addition to the main method, Project2 provides several public static methods.

See the online documentation for more details.

IBM.java (documentation)

This interface defines a few constants. The constant METALS indicates the number of metal (3), the constants GOLD, PLATINUM, and URANIUM give mnemonic names for the codes 0, 1, and 2, and the array metalName can be used to translate these numbers into strings.

StopThread.java (documentation)

A trivial exception that extends RuntimeException. A thread can "commit suicide" by throwing this exception. You should never catch it. It is an "unchecked" exception, so there's no need to declare that a method throws StopThread.

Refiner.java (documentation)

This Runnable class has a constructor and methods run and getProduction. The run method goes through a number of iterations specified in the constructor. On each iteration, it produces a random amount of a random metal and delivers it to the appropriate broker by calling its deliver method. When it finishes the designated number of iterations, it waits three seconds and then shuts down the entire program by calling System.exit(0). Consumer threads will probably see an InterruptedExpression. Each wait() in your program should be inside a try statement such as

    try {
        wait();
    } catch (InterruptedException e) {
        Project2.debug(... whatever ...);
        throw new StopThread();
    }
The throw is important; without it, your program will just hang, since the main method does a join on each of the consumer threads before exiting.

The getProduction() method is used by Project2.main to audit the global state when the system shuts down.

Consumer.java (documentation)

This Runnable class is also a simple Runnable. It iterates forever generating random orders and calling the get method of random brokers. It also has a getConsumption method used by Project2.main to audit the global state when the system shuts down.

Broker.java

This is an interface. You must write a class called BrokerImplementation that implements this interface. (The name of your class must be spelled exactly this way.) Your class must implement the three methods specified in the interface, as well as a constructor that has one integer argument. All three methods should be protected against race conditions, but you will probably find that they cannot all be synchronized methods.

Hints

Remember the cardinal rule of concurrent programming:
Any variable that may be accessed by more than one process should only be accessed inside a critical section.
In the context of this project, that means that fields of class BrokerImplementation should only be accessed inside synchronized methods. On the other hand, there's another rule that will help you avoid deadlocks:
A synchronized method should never call a synchronized method of another object.
In the context of this project, that means that BrokerImplementation.get cannot be synchronized because it needs to call BrokerImplementation.swap in another broker. Instead, define your own private synchronized methods to read and/or update fields of BrokerImplementation and call them from BrokerImplementation.get.

There will undoubtedly be more hints provided by your fellow students. Watch the Frequently Asked Questions (FAQ) for more information.

What to turn in

Turn all .java files you wrote or modified. Do not turn in .class files. No transcript is necessary.

Grading

Please carefully consider all the grading criteria discussed in class. Correctness will be 70% of your grade, and style will be 30% of your grade.

1 However, at first you should probably look only at the first 3 questions in the FAQ. The remaining questions involve "advanced" topics that will only confuse you if you're trying to get the basic functionality working.

2The constants METALS, GOLD, PLATINUM, and URANIUM are defined in interface IBM, but because Consumer implements IBM, it is ok to omit "IBM." from IBM.GOLD, etc.


Last modified: Fri Feb 20 2:55:01 CST 2004 by Anoop Gupta