views:

217

answers:

7

The assignment is as follows:

The gas station consists of 2 pumps. Each pump has a certain amount of fuel it can distribute. Cars arrive at random intervals and attempt to use one of two pumps:

- If a pump is available and has fuel, the car is immediately allowed to use it. Each car requires a certain amount of fuel (random number), and has to wait for a time proportional to that amount of fuel. For example, a car may need 6 gallons and will use the pump for 3sec, another car may need 10 gallons and will use the pump 5 seconds, etc. When the car is fueled up, it leaves and the another car can use the pump. After fueling a car, the amount of fuel in the pump is adjusted accordingly.
- If both pumps are currently being used, then an arriving car waits until one of the two pumps becomes available.
- If a pump runs out of fuel, it must wait for a tanker to provide more fuel. The tanker arrives periodically (but not too often), and fills both pumps to capacity. While a tanker is servicing the pumps, no cars can use the pumps. forgot to add this

Part I: you must submit a detailed design that matches the above specifications. Your design must use Java threads. You must specify how many and what type of threads you will be using, and how these threads will be synchronized. You can write this stage of the project in pseudo-code. This is to help you understand how the various pieces will together.

Part II: you must submit a complete implementation of your design using Java threads and appropriate synchronization methods. Your implementation must be carefully tested against the above specifications.


I want to know. How can I use a Java Thread to simulate the cars coming in at random intervals?
I am very lost and appreciate your help in advance.

+3  A: 

If you have fixed intervals the number of cars arriving in that interval is Poisson distributed.

The time between two cars has a probabilitydensity proportional to exp(-t/tau) where tau describes the frequency of cars arriving. So you need to figure out how to create exponentially distributed random numbers.

From a probability density of p(t)=c*exp(-t/tau) we integrate a cumulative probability distribution of P(t)=1-exp(-t/tau). So inverting that function you get t=-tau*ln(1-P(t)). So if you generate a number u uniformly distributed between 0 and 1 you can get a correctly distributed t as t=-tau*ln(1-u)

CodeInChaos
Poisson distribution is definitely what you want.
Steve McLeod
how is Poisson distribution related to solving the OP's problem? i.e. `How can I use a Java Thread to simulate the cars coming in at random intervals?`
Lie Ryan
For a class exercise I'd start with a uniform distribution using `Random` to generate numbers. Once this is working go for a Poisson for the extra credits.
Qwerky
This is of no help a) it does not satisfy the requirement b) it adds enormous complexity for a novice.
Justin
I don't think this is specifically what the question is getting at - it seems to be much more complex than what is required
stark
Using a uniformly distributed random variable for waiting time isn't a good description of reality. That's like arguing that because throwing a die hasn't resulted in a 6 for the last five turns it must be a six on the next throw. So I'm arguing that he shouldn't sleep for a random uniform interval, but to calculate the sleeping time as t from my post.
CodeInChaos
@Lie Ryan if the question is 'how can I use a banana to undo a bolt' then an answer describing an Allen key is better than an answer about fruit. Threads and generating randomness are unrelated, vagarities of the scheduler not withstanding.
Pete Kirkham
I actually think this is closer a Markov property than Poisson.
San Jacinto
+12  A: 

Create a Car factory class that spits out a Car to be added to a dequeue and goes to sleep for a random period of time.

Like all students, you're probably finding this problem to be a little overwhelming. It is if you don't start breaking it down into smaller chunks that you can handle. Think of an overall design and start implementing small pieces of it.

For example, this is a queuing theory problem. They could be cars, people in bank lines, or anything interacting with a queue. Don't worry about the cars or the gas station details. Here's your issue:

  1. You've got a line that adds new entries at one end and takes them off at the other. It's called a dequeue data structure. Read up on that. See if you can write (or reuse) a Java Dequeue class. Understand it completely. Write a small driver to add to one end and remove from the other.
  2. Once you have that, you need to write classes that create new entries to add to the dequeue and another to remove them. Start simply by writing adders/removers that work at a fixed interval. What you should see is that if the adder and remover have exactly the same interface, the number of entries waiting in line will not change. If the adder works faster than the remover, the line should fill up. If the remover works faster than the adder, you'll never have a backup. Make sure that your simple classes exhibit this kind of behavior.
  3. Add in the random bits and start your simulation. You'll want to see how the number of entries in line changes over time.
  4. Now add more than one line. You want to see how adding more lines changes the dynamics.
duffymo
Thread.currentThread().sleep(1000)
Ziplin
1000 isn't random; that's one every second.
duffymo
can i do Random r = new Random(); Thread.currentThread().sleep(r.nextInt(100000))
Luron
@Luron yes you can do that, you could also sleep for a fixed time and do a random check to decide whether to create a new car ie. if (new Random.nextInt(100) < 10) // 10% chance to create a car every run.
Justin
@duffymo i am beyond overwhelmed. haha. where do you suggest i begin with this project?
Luron
An excellent answer! Very nice help!
San Jacinto
It's basically a thread pool. You can have a thread for each pump who are the consumers (they pop from the dequeue) and the car factory is the producer (push to dequeue). You'll probably have to be careful with simultaneous access to the dequeue.
Matt H
@Luron - start simple and add complexity. If you're allowed to use Java built-in collections, I'd start with this: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html. Take a long, hard look at BlockingDequeue. Understand it completely; give it a try with some simple problems; do a Google search for some examples. You're learning; start slowly and accelerate as you understand more.
duffymo
You don't need a deque; a simple queue is enough. (You're only ever adding at one end and removing at the other.)
Donal Fellows
A: 

You can use same kind of cars source. You can establish some time interval for example with random deviation.

Asar
+1  A: 

I can see where you're going with a thread, but you don't really need one unless this is a graphic simulation in which you wish people to see it run in real time. Otherwise, simply keep track of a timeline. Know at any given point in time what event is going to happen next between: A) Truck arrives. B) Car arrives. C) Car leaves.

I imagine you're keeping track of how long these things take, so simply simulate the event to happen sooner. And everytime a car arrives, the time it takes for a new car to arrive will be a random amount of time decided by you.

Trust me, it'll make life a lot easier for you to simply things.

Neil
forgot to add this ***Part I: you must submit a detailed design that matches the above specifications. Your design must use Java threads.* You must specify how many and what type of threads you will be using, and how these threads will be synchronized. You can write this stage of the project in pseudo-code. This is to help you understand how the various pieces will together. ** Part II: you must submit a complete implementation of your design using Java threads and appropriate synchronization methods. Your implementation must be carefully tested against the above specifications.
Luron
Well if it's an exercise on using Java threads, you should do it. However, know that this is not a suitable scenario for a thread in any practical context.
Neil
A: 

You can use the thread-safe PriorityBlockingQueue to create an event queue.

Basically, car arrivals, tanker arrivals, car entering pump, and car exiting a pump are all events. Each of these have an order of occurrence, you insert an "Event" object for each of these events, with a timestamp. You can arrange so that the timestamp is used by the PriorityBlockingQueue to sort the events.

Initially, you start a thread for the car arrival producer thread and tanker arrival producer thread. The car arrival thread will put() a CarArrivalEvent to the queue, and then sleep for an random amount of time. The tanker thread also does the same, but put() TankerArrivalEvent instead.

The gas station has two pumps, each represented by consumer threads. Each pump thread will take() a CarArrivalEvent, then sleep for the amount of time needed to fill the car. You do similarly for TankerArrivalEvent.

Lie Ryan
A: 

Don't Use a Poisson Distribution. Poission will give you "Number arrivals in next X minutes." It will not give you "Time until next arrival".

Wite a small while loop like so ::

  public int getTimeTillNextCar() {
    PROBABILITY = .001;
    int timeTillNextCar = 0;
    while(rand.nextDouble() > PROBABILITY) {
      timeTillNextCar++;
    }
  }

Obviously, I just assumed you are using discreet time. However, it is possible (and some would argue better) to use a single draw from an exponential. This will be more efficent. However, using that approach makes the code "mathy" which some people might not like/understand.

Remeber, the Poisson distribution arrives from counting how many bernoulli draws were succesful given n draws when p is very small and n is moderately big. If n is "too" big then the Possion distribution will converge to the Normal distribution.

As for the rest of the design...

Thread_A should add cars to a Queue (be sure to use a thread safe queue class)

Thread_A shoule do this:
add car,
sleep(getTimeTillNextCar()),
add car,
sleep(getTimeTillNextCar()),
add car,
sleep(getTimeTillNextCar()),
etc....

Thread_B and Thread_C should take cars off the queue:
Thread_B (and C) should do this:
get_car_off_queue,
sleep(car.getFuelingTime(),
get_car_off_queue,
sleep(car.getFuelingTime(), etc...

Ivan
If you have two threads representing the pumps, then it doesn't fit the problem specification - the problem says that "if a pump is available and has fuel, the car is immediately allowed to use it". If you are not running in a RTOS, then there is no guarantee that the thread for a free pump will be scheduled and dequeue a car.
Pete Kirkham
Pete Kirkham, in da house...
duffymo
@Pete -- True, but that's a pretty easy problem to fix. Handling the "no queue" case isn't going to derail this general setup.
Ivan
+1  A: 

Firstly, as there is nothing in either your OP nor the extra bit of the problem statement which states that the system is operating against the wall clock, don't assume it does. Anything based on Sleeping for ten seconds between creating cars will drive you crazy while you're testing it. Create a simple interface to provide time for the simulation and work against that; if you need to tie it to the wall clock then you can, but you can also run your tests as fast as your machine will go.

Secondly, it's usually better to run simulations as events - car arrives at station, cars transitions from queue to pump, car leaves pump, tanker arrives. Usually a priority queue of events based on their times works; when a car starts filling, you add the event for it completing its task to the event queue with a timestamp in the future. It's much, much easier to write logic not to process cars if there is a tanker at a given time than to mess around with threading priorities.

Since your task requires that you demonstrate some synchronisation between threads, you might want to run the processes of cars waiting, cars filling/tankers unloading as separate threads ( in real software you wouldn't, but more likely use futures and an executor if you wanted parallel execution, but I'm assuming this is a pedagogic task and you need to show some design of threads, rather than letting the library sort it all out for you ).

So for each time slice, you process the events from the queue, wait for all event processing to complete, and then ask the clock for the next tick. The fast clock will immediately return a timestamp for the next second, or a wall clock clock would wait until the next second of the system time.

Since you're required to use threads for each task, you need to synchronise these tasks at the start and end of each time slice, and you need to synchronise or otherwise ensure that enqueued events are safely enqueued and visible before a time slice finishes.

So the tasks are something like:

  • incoming cars

    • every second, determine the number of car arrivals. this will be a Poisson distribution.
    • for each arrival, post a car arrived event ( or post an event with the number of cars) (alternatively, use some other random mechanism; most of the other approaches will only cause one car to arrive at a time, which is not often a useful restriction to place on a model)
  • incoming tankers

    • every (tanker arrival period) post a tanker arrived event per pump
  • waiting cars

    • increment the number of cars waiting on car arrival event
  • pumps

    • if a tanker has arrived, set the tanker waiting flag
    • if the pump is free, then
      • if a tanker is waiting, reset the tanker waiting flag, fill pump, post pump free event for time-to-fill-pumps in future
      • if the pump has fuel and any car is waiting, decrement the cars waiting count, post pump free event for time-to-fill-car in future

The problem statement isn't clear whether the tanker has to wait for both pumps to be free before it can start filling them, in which case you would need to add another 'tanker ready' state.

If the tasks are in different threads, you would need to synchronise the various counters, either 'manually' or by using the atomic values in java.util.concurrent.atomic.

Pete Kirkham