3.7 Gas Station Simulation Problem

 < Day Day Up > 



3.7 Gas Station Simulation Problem

A program using threads will now be implemented in a domain that is very much amenable to the techniques in this chapter: simulation problems. The problem presented here is to simulate a gas station. Section 3.7.1 introduces the problem and it is solved in Section 3.7.2.

3.7.1 Problem Statement

A gas station is to be modeled to calculate the average time a driver spends getting gas. The time starts when the driver begins waiting for a pump and ends when the car leaves the pump. The simulation starts with 50 cars arriving at the gas station randomly between 0 and 30 seconds after the simulation begins. The driver in each car will first check to see if the pump is free. If the pump is not free, the driver will wait until the pump is free. Once the pump is free, the driver will pull the car up to the pump and shut off the engine. For this simulation, this will take .5 second. After the engine has been turned off, the driver will unlock the door of the car and open the door, which takes an additional .5 second. The driver will then close the car door, which will take a negligible amount of time. The driver then walks to the pump, turns the pump on, and selects a grade of gas. This also takes .5 second.

The possible grades of gas that can be selected are low octane (87 octane), medium octane (89 octane), and high octane (91 octane), where the octane number is the average of the motor octane number and the research octane number. Motor octane is calculated by running the gasoline in a standard engine, and research octane is calculated by doing a weighted sum of the components in the gasoline. The octane number on the pump is always the average of the two.

When the driver has turned on the pump and selected the grade of gasoline, he will put the gas nozzle in the fuel intake for the gas tank for the car. Once again, this will take .5 second in this simulation. Also in this simulation, filling the tank with gasoline will take 2.5 seconds. The driver then puts the nozzle back in the pump (which takes another .5 second), opens the car door, and leaves the pump, taking a final .5 second. So the total time that the driver is at the pump is 6 seconds. Once the driver leaves the pump, the pump is free and another driver may use the pump. Write a simulation of this gas station.

3.7.2 Gas Station Simulation

This gas station simulation is instructive in that it is more like realworld problems. In this problem, programmers are not given too little information; rather, they are given too much information, most of it totally irrelevant. For example, the simulation has nothing to do with octane, so the entire paragraph about the octane number can be disregarded. But what other information is important?

Programmers who attempt to use object-oriented programming (OOP) on this problem will be faced with many red herrings. They will be creating objects for doors with locks, nozzles, and fuel tanks because they are in the problem statement. They may start creating dials on the pumps, because the pumps they have seen in the real world have dials to show how much gas is sold, or may try to address the issue of payment, because gas is not free. Left to their own devices, programmers can become very creative in finding ways to obfuscate a simple problem.

Programmers should not be interested in objects just because they may exist in the problem statement or possibly in the real world. They should be concentrating on objects that are actually needed to solve the problem. Do we need to model the doors on the car? Or even the driver? What is missing is a concise statement of the problem, one which can then drive the decisions of the objects required to solve the problem. That is why writing a description of the problem is always the first step in writing a program.

This problem is simple because programmers can simply take a few sentence fragments from the description given and come up with a valid statement of the problem. Doing this, we see that the problem can actually be described as:

A gas station is to be modeled to calculate the average time a driver spends getting gas. The time starts when the driver begins waiting for a pump and ends when the car leaves the pump. The simulation starts with 50 cars arriving at the gas station randomly between 0 and 30 seconds after the simulation begins. Once the pump is free, the driver will pull the car up to the pump. The total time that the driver is at the pump is 6 seconds. When the driver leaves the pump, the pump is free and another driver may use the pump.

In the real world, defining the actual problem is seldom this easy, but it is extremely important. Programmers who begin to create a program without first describing what they are doing are bound to create useless objects and other artifacts that will only create confusion.

Given the description of the problem, one active object is necessary. This object will be modeled in this program as a car object. The car is active and has the following behavior: It waits a random amount of time between 0 and 30 seconds. It then tries to use the pump, and when the pump is free it pulls up to the pump, pumps gas, and leaves the pump. To match the car object we now need a pump object. This object will have two states: The pump is BUSY or the pump is FREE. The state diagram for the pump is given in Exhibit 6. Implementation of these car and customer objects is shown in Program3.2a and Program3.2b (Exhibits 7 and 8).

Exhibit 6: State Diagram for Gas Pump Problem

start example

click to expand

end example

Exhibit 7: Program3.2a: Car Class

start example

 import java.util.*; class Car implements Runnable {   private static int totalTime = 0,//Total time spent by all                                    //cars        totalCars = 0;              //Total number of cars   private int customerNumber;      //The customer number to set                                    //Random value, and for                                    //intermediate output   private Pump myPump;             //The pump the customer                                    //should use   /**    * Constructor: Set the customerNumber and pump.    */   public Car(int customerNumber, Pump pump) {     this.myPump = pump;     this.customerNumber = customerNumber;   }   /**    * Static function to calculate average at the end of    * simulation.    */   public static float calcAverage() {     return totalTime/totalCars;   }   /**    * Thread that implements the pump.    */   public void run() {     //Declare variables needed for simulation.     final int WAIT_TIME = 30000;     long startTime, endTime;     Random random = new Random(customerNumber);     int waitTime = random.nextInt(WAIT_TIME);     //Wait a random amount of time before coming to pump.     try {       Thread.sleep(waitTime);     } catch (InterruptedException e) {     }     //use the pump, pump the gas, and leave.     System.out.println("Customer "+ customerNumber +                " arrives at pump");     startTime = (new Date()).getTime();     myPump.usePump();     System.out.println("Customer "+ customerNumber +                " pumps gas");     myPump.pumpGas();     System.out.println("Customer "+ customerNumber +                " leaves pump");     myPump.leave();     endTime = (new Date()).getTime();     System.out.println("Time = "+ (endTime - startTime));     //Update the variables to calculate the average. If this is     //the last car, let the main() finish and print the average.     //Note that to use the static variables we need to get the     //lock on the class.     synchronized(Car.class) {       totalTime + = (endTime - startTime);       totalCars++;     }   } } 

end example

Exhibit 8: Program3.2b: Pump Class

start example

 class Pump {   private static final int FREE = 0;   private static final int BUSY = 1;   private int state = FREE;   /**    * Method to call when a car first wishes to use a pump. It    * adds a 1/2 second to the simulated time in the problem.    */   synchronized public void usePump() {     try {       //Pre-condition processing (guard)       while(true) {         if (state = = FREE)           break;         wait();       }       //Simulate pulling to the pump by waiting 1/2 second.       Thread.sleep(500);       //Post-condition processing, change state.       state = BUSY;       notifyAll();     } catch (InterruptedException e) {     }   }   /**    * Simulate pumping the gas by waiting 5 seconds.    */   synchronized public void pumpGas() {     try {       //Pre-condition processing (guard)       while(true) {         if (state = = BUSY)           break;         wait();       }       //Simulate pumping gas by waiting 5 seconds.       Thread.sleep(5000);       //Post-condition processing, no change state needed.     } catch (InterruptedException e) {     }   }   /**    * Leave the pump, freeing it for the next customer.    */   synchronized public void leave() {     try {       //Pre-condition processing (guard)       while(true) {         if (state = = BUSY)           break;         wait();       }       //Simulate leaving the pump by waiting 1/2 second.       Thread.sleep(500);       //Post-condition processing, change state       state = FREE;       notifyAll();     } catch (InterruptedException e) {     }   } } 

end example

All that remains is to implement the controlling object, the GasStation, which is shown in Exhibit 9 (Program3.2c). This will create the objects, run the simulation, and create the answer. Note that some method of notifying the main thread when all the cars have finished running has to be implemented. In this case, the main thread is "joined" with all the child threads. This task can be accomplished in many ways, and some of the problems at the end of this chapter explore those options.

Exhibit 9: Program3.2c: Gas Station Class

start example

 public class GasStation {   static final int TOTAL_CARS = 10;   public static void main(String args[]) {     Thread carThreads[] = new Thread[TOTAL_CARS];     try {       //Create the monitor (passive object).       Pump pump1 = new Pump();       //Start all the Car threads       for (int i = 0; i < TOTAL_CARS; i++) {         Car car = new Car(i, pump1);         (carThreads[i] = new Thread(car)).start();       }       //Now suspend and wait for simulation to finish.       for (int i = 0; i < TOTAL_CARS; i++) {         carThreads[i].join();       }     } catch (InterruptedException e) {     }     //Print average time at the end of the simulation.     System.out.println("Average time to get gas = "+       Car.calcAverage());   } } 

end example

Many programmers who see this solution do not like it. After all, a car does not literally pump gas, and many of the objects in the original problem are missing. This bothers many programmers, particularly programmers just learning object-oriented programming. They have come to believe that somehow the real world can be represented in the computer. The real world has cars, pumps, doors, drivers, etc., and if these can be abstracted and put into a program then the problem can be magically solved. But, a computer does not have cars and pumps; it has 1's and 0's. You cannot represent the real world in a computer; you can simply create an abstract model of it. When an attempt is made to represent the real world in a computer, the problems become hopelessly complex because the real world is hopelessly complex. What parts of the real world are actually built into the abstract model depends on the problem to be solved. What are the boundaries and constraints of the problem? What is the result to be produced? These are the important questions, not what objects can be found (or imagined to be present) in the real world.



 < Day Day Up > 



Creating Components. Object Oriented, Concurrent, and Distributed Computing in Java
The .NET Developers Guide to Directory Services Programming
ISBN: 849314992
EAN: 2147483647
Year: 2003
Pages: 162

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net