In this activity we simulate liquid flowing in and out of a storage tank. The methods wait and notifyAll will be used to coordinate the threads responsible for filling and emptying the vessel.
In addition to the Solution document, the project for this activity contains the following classes:
The class StorageTank has two data fields:
and two public methods:
At present the inflow and outflow are uncoordinated, so that when the simulation is executed it runs for a period of time, but eventually an exception is thrown and the program halts. The objective is to modify the methods in and out so that a thread which attempts to add liquid to a full tank, or take liquid from an empty one is blocked, pending a signal that the other thread has changed the state of the tank.
In some ways the simulated storage tank resembles a buffer, although it is much less complex because its state simply consists of a single number, instead of there being a queue of stored items to manage.
Run the program. You should find that sooner or later an exception is always thrown. You may like to experiment with different tank capacities, by changing the argument passed to the StorageTank constructor in the main method. Exactly what happens will vary from run to run, and will depend to a certain extent on your computer. You may see a thread continue for a number of steps after the exception is reported.
Now make changes to the methods in and out so that the threads use wait and notifyAll to coordinate their activities and no longer cause exceptions to be thrown.
Because in and out are already declared as throwing an exception (which is caught elsewhere) it is not essential to enclose wait in a try and catch block.
Compile and run the revised program. If the changes are correct it should now run indefinitely and no exceptions should be thrown. You will need to stop the program, since it won't halt automatically.