For this assignment, you will write a trading system to supply Brewers with the four most common grains used in production of beer: corn, barley, rice, and wheat. The program will manage a single supplier and any number of brewers, as well as four traders who are responsible for stocking and delivering grain to brewers that request it.
Each trader maintains a stock of all four types of grain, but is a “specialist” for only one of them, called its specialty. From time to time, the supplier delivers a shipment of grain to the trader that specializes in that type of grain. For example, the supplier might deliver 30 bushels of barley to the BARLEY trader, and later it might deliver 20 bushels of wheat to the WHEAT trader. Brewers periodically place purchase orders with Traders. Each order specifies a number of bushels of each type of grain. An order can be placed with any trader; in this program Brewers choose Traders at random. A Trader will fill the order from its own stock if possible. If the specialist for grain G cannot fill an order because it does not have enough G on hand, it just waits until it gets more from the Supplier. If it is short of some grain that is not its specialty, it attempts to get more by trading with the specialist for that grain. In any case, the trader does not respond to the brewer until it can fill its entire order. To keep things simple, we will assume, somewhat unrealistically, that bushels of corn, barley, wheat, and rice are all equally valuable. That is, three bushels of corn can be swapped for three bushels or wheat, three bushels of barley, etc.
For example, suppose a brewer places an order with the WHEAT trader for for 4 bushels of wheat and 1 bushel of barley.
A trader treats a request from another trader just like an order from a brewer. If it can fill it immediately, it will. Otherwise, since the request must be for its specialty grain, it will just wait until it gets more from the supplier.
We have supplied four classes, P2, Supplier, Brewer, and Order; one enumeration, Grain; and and one interface, Trader. The classes Supplier and Brewer are meant to be used as threads (that is, they implement Runnable). You are expected to write a class TraderImpl that implements Trader. TraderImpl is a “monitor” class, meaning that a Trader does not act on its own, only in response to a call from a Supplier or Brewer. P2 is the main class. It creates one Supplier thread and some number (specified on the command line) of Brewer threads and starts them running.
From time to time the Supplier thread delivers a load of some grain to the specialist for that grain by calling the Trader method
public void deliver(int bushels);From time to time a Brewer places an order by contacting a random Trader and calling the Trader method
public void get(Order order);The order order contains one non-negative integer for each type of grain, indicating how much of that grain is desired. For example, to get three bushels of wheat and one bushel of barley from the BARLEY Trader, a Brewer might use code like this:
Order order = new Order(); order.set(Grain.WHEAT, 3); order.set(Grain.BARLEY, 1); P2.specialist(Grain.BARLEY).get(order);As you can see, the class P2 provides several handy utilities as static methods. We will explain these in more detail below.
A Trader who does not have enough of a grain on hand to satisfy a request may try to get more from the specialist in that grain by calling the method
public void swap(Grain what, int amt);This method indicates that the calling Trader is willing to swap amt bushels of grain what for amt bushels of the supplier's specialty. For example, the call
P2 . specialist(Grain.WHEAT) . swap(CORN, 2);indicates that the caller is willing to swap 2 bushels of corn for two bushels of wheat. 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 corn and add 2 to its supply of wheat.
When a Trader cannot satisfy a get or swap request because it does not have enough of its specialty grain, it blocks the caller (using the Java wait method) until it can. A Trader that is blocked waiting for something should continue to accept calls from the Suplier, Brewers, or other Traders.
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 brewer who repeatedly gets passed over).
mkdir project2 cd project2 cp ~cs537-1/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.
In addition to the main method, P2 provides several public static methods.
Your code should not catch InterruptedException. Any method that contains a call to a method that throws InterruptedException should simply declare that it throws InterruptedException in its header.
The getProduction() method is used by P2.main to audit the global state when the system shuts down.
Any variable that may be accessed by more than one process and modified by any of them should only be accessed inside a critical section.In the context of this project, that means that fields of class TraderImpl 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.There are exceptions to this rule, but they are rare. In the context of this project, it means that TraderImpl.get cannot be synchronized because it needs to call TraderImpl.swap in another Trader. Instead, define your own private synchronized methods to read and/or update fields of TraderImpl and call them from TraderImpl.get.
There will undoubtedly be more hints provided by your fellow students. Watch the Frequently Asked Questions (FAQ) for more information.
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.