Title: Discrete Event Simulation
1Discrete Event Simulation
- CS1316 Representing Structure and Behavior
2Story
- Discrete event simulation
- Simulation time ! real time
- Key ideas
- A Queue
- A Queue is a queue, no matter how implemented.
- Different kinds of random
- Straightening time
- Inserting it into the right place
- Sorting it afterwards
- Building a discrete event simulation
- Graphics as the representation, not the real
thing The Model and the View
3Imagine the simulation
- There are three Trucks that bring product from
the Factory. - On average, they take 3 days to arrive.
- Each truck brings somewhere between 10 and 20
productsall equally likely. - Weve got five Distributors who pick up product
from the Factory with orders. - Usually they want from 5 to 25 products, all
equally likely. - It takes the Distributors an average of 2 days to
get back to the market, and an average of 5 days
to deliver the products. - Question we might wonder How much product gets
sold like this?
4Dont use a Continuous Simulation
- We dont want to wait that number of days in real
time. - We dont even care about every day.
- There will certainly be timesteps (days) when
nothing happens of interest. - Were dealing with different probability
distributions. - Some uniform, some normally distributed.
- Things can get out of synch
- A Truck may go back to the factory and get more
product before a Distributor gets back. - A Distributor may have to wait for multiple
trucks to fulfill orders (and other Distributors
might end up waiting in line)
5We use a Discrete Event Simulation
- We dont simulate every moment continuously.
- We simulate discrete events.
6Whats the difference?No time loop
- In a discrete event simulation There is no time
loop. - There are events that are scheduled.
- At each run step, the next scheduled event with
the lowest time gets processed. - The current time is then that time, the time that
that event is supposed to occur. - Key We have to keep the list of scheduled events
sorted (in order)
7Whats the difference?Agents dont act()
- In a discrete event simulations, agents dont
act(). - Instead, they wait for events to occur.
- They schedule new events to correspond to the
next thing that theyre going to do. - Key Events get scheduled according to different
probabilities.
8Whats the difference?Agents get blocked
- Agents cant do everything that they want to do.
- If they want product (for example) and there
isnt any, they get blocked. - They cant schedule any new events until they get
unblocked. - Many agents may get blocked awaiting the same
resource. - More than one Distributor may be awaiting arrival
of Trucks - Key We have to keep track of the Distributors
waiting in line (in the queue)
9Key Ideas
- A Queue
- A Queue is a queue, no matter how implemented.
- Different kinds of random
- Straightening time
- Inserting it into the right place
- Sorting it afterwards
10Key idea 1 Introducing a Queue
- First-In-First-Out List
- First person in line is first person served
I got here second!
I got here third!
I got here first!
This is the front or head of the queue
This is the tail of the queue
11First-in-First-out
- New items only get added to the tail.
- Never in the middle
- Items only get removed from the head.
I got here second!
I got here third!
I got here first!
This is the front or head of the queue
This is the tail of the queue
12As items leave, the head shifts
I got here second!
I got here third!
I got here first! AND NOW IM UP!
Now, this is the front or head of the queue
This is the tail of the queue
Served!
13As new items come in, the tail shifts
I got here second!
I got here third!
I got here fourth!
Now, this is the tail of the queue
Now, this is the front or head of the queue
14What can we do with queues?
- push(anObject) Tack a new object onto the tail
of the queue - pop() Pull the end (head) object off the queue.
- peek() Get the head of the queue, but dont
remove it from the queue. - size() Return the size of the queue
15Building a Queue
- gt Queue line new Queue()
- gt line.push("Fred")
- gt line.push("Mary")
- gt line.push("Jose")
- gt line.size()
- 3
16Accessing a Queue
- gt line.peek()
- "Fred"
- gt line.pop()
- "Fred"
- gt line.peek()
- "Mary"
- gt line.pop()
- "Mary"
- gt line.peek()
- "Jose"
- gt line.pop()
- "Jose"
- gt line.pop()
- java.util.NoSuchElementException
We dont really want to peek() or pop() an empty
queue, so we should probably check its size first.
17Building aQueue
- import java.util. // LinkedList representation
- /
- Implements a simple queue
- /
- public class Queue
- / Where we'll store our elements /
- public LinkedList elements
-
- /// Constructor
- public Queue()
- elements new LinkedList()
-
18Queue methods
- /// Methods
-
- / Push an object onto the Queue /
- public void push(Object element)
- elements.addFirst(element)
-
-
- / Peek at, but don't remove, top of queue /
- public Object peek()
- return elements.getLast()
-
- / Pop an object from the Queue /
- public Object pop()
- Object toReturn this.peek()
- elements.removeLast()
- return toReturn
-
-
- / Return the size of a queue /
Were using a linked list to implement the
Queue. The front of the LinkedList is the
tail. The last of the LinkedList is the head.
19A queue is a queue, no matter what lies beneath.
- Our description of the queue minus the
implementation is an example of an abstract data
type (ADT). - An abstract type is a description of the methods
that a data structure knows and what the methods
do. - We can actually write programs that use the
abstract data type without specifying the
implementation. - There are actually many implementations that will
work for the given ADT. - Some are better than others.
20Array-oriented Queue
- /
- Implements a simple queue
- /
- public class Queue2
-
- private static int ARRAYSIZE 20
-
- / Where we'll store our elements /
- private Object elements
-
- / The indices of the head and tail /
- private int head
- private int tail
21Queue array head index tail index
- /// Constructor
- public Queue2()
- elements new ObjectARRAYSIZE
- head 0
- tail 0
-
22Queue2methods
- / Push an object onto the Queue /
- public void push(Object element)
- if ((tail 1) gt ARRAYSIZE)
- System.out.println("Queue underlying
implementation failed") -
- else
- // Store at the tail,
- // then increment to a new open position
- elementstail element
- tail
-
- / Peek at, but don't remove, top of queue /
- public Object peek()
- return elementshead
-
- / Pop an object from the Queue /
- public Object pop()
- Object toReturn this.peek()
- if (((head 1) gt ARRAYSIZE)
As the queue gets pushed and popped, it moves
down the array.
23Same methods, same behavior
- Welcome to DrJava.
- gt Queue2 line new Queue2()
- gt line.push("Mary")
- gt line.push("Kim")
- gt line.push("Ron")
- gt line.peek()
- "Mary"
- gt line.pop()
- "Mary"
- gt line.peek()
- "Kim"
- gt line.size()
- 2
- gt line.pop()
- "Kim"
- gt line.pop()
- "Ron"
But can only handle up to 20 elements in the
queue! Less if pushing and popping. Could shift
elements to always allow 20. Not as good an
implementation as the linked list implementation.
(But uses less memory.)
24Key idea 2 Different kinds of random
- Weve been dealing with uniform random
distributions up until now, but those are the
least likely random distribution in real life. - How can we generate some other distributions,
including some that are more realistic?
25Visualizing a uniformdistribution
- import java.util. // Need this for Random
- import java.io. // For BufferedWriter
- public class GenerateUniform
- public static void main(String args)
- Random rng new Random() // Random Number
Generator - BufferedWriter outputnull // file for
writing -
- // Try to open the file
- try
- // create a writer
- output
- new BufferedWriter(new FileWriter("D/cs13
16/uniform.txt")) - catch (Exception ex)
- System.out.println("Trouble opening the
file.") -
- // Fill it with 500 numbers between 0.0 and
1.0, uniformly distributed - for (int i0 i lt 500 i)
- try
By writing out a tab and the integer, we dont
have to do the string conversion.
26How do we view a distribution?A Histogram
27Then graph the result
28A Uniform Distribution
29A NormalDistribution
- // Fill it with 500 numbers between -1.0 and
1.0, normally distributed - for (int i0 i lt 500 i)
- try
- output.write("\t"rng.nextGaussian())
- output.newLine()
- catch (Exception ex)
- System.out.println("Couldn't write the
data!") - System.out.println(ex.getMessage())
-
-
30Graphing the normal distribution
The end arent actually highthe tails go further.
31How do we shift the distribution where we want it?
- // Fill it with 500 numbers with a mean of 5.0
and a - //larger spread, normally distributed
- for (int i0 i lt 500 i)
- try
- output.write("\t"((range
rng.nextGaussian())mean)) - output.newLine()
- catch (Exception ex)
- System.out.println("Couldn't write the
data!") - System.out.println(ex.getMessage())
-
-
Multiply the random nextGaussian() by the range
you want, then add the mean to shift it where you
want it.
32A new normal distribution
33Key idea 3 Straightening Time
- Straightening time
- Inserting it into the right place
- Sorting it afterwards
- Well actually do these in reverse order
- Well add a new event, then sort it.
- Then well insert it into the right place.
34Exercising an EventQueue
- public class EventQueueExercisor
- public static void main(String args)
- // Make an EventQueue
- EventQueue queue new EventQueue()
-
- // Now, stuff it full of events, out of
order. - SimEvent event new SimEvent()
- event.setTime(5.0)
- queue.add(event)
-
- event new SimEvent()
- event.setTime(2.0)
- queue.add(event)
-
- event new SimEvent()
- event.setTime(7.0)
- queue.add(event)
- event new SimEvent()
Were stuffing the EventQueue with events whose
times are out of order.
35If it works right, should look like this
- Welcome to DrJava.
- gt java EventQueueExercisor
- Popped event time0.5
- Popped event time1.0
- Popped event time2.0
- Popped event time5.0
- Popped event time7.0
36Implementing an EventQueue
- import java.util.
- /
- EventQueue
- It's called an event "queue," but it's not
really. - Instead, it's a list (could be an array, could
be a linked list) - that always keeps its elements in time sorted
order. - When you get the nextEvent, you KNOW that it's
the one - with the lowest time in the EventQueue
- /
- public class EventQueue
- private LinkedList elements
-
- /// Constructor
- public EventQueue()
- elements new LinkedList()
-
37Mostly, its a queue
- public SimEvent peek()
- return (SimEvent) elements.getFirst()
-
- public SimEvent pop()
- SimEvent toReturn this.peek()
- elements.removeFirst()
- return toReturn
-
- public int size()return elements.size()
-
- public boolean empty()return this.size()0
38Two options for add()
- /
- Add the event.
- The Queue MUST remain in order, from lowest
time to highest. - /
- public void add(SimEvent myEvent)
- // Option one Add then sort
- elements.add(myEvent)
- this.sort()
- //Option two Insert into order
- //this.insertInOrder(myEvent)
-
39There are lots of sorts!
- Lots of ways to keep things in order.
- Some are faster best are O(n log n)
- Some are slower theyre always O(n2)
- Some are O(n2) in the worst case, but on average,
theyre better than that. - Were going to try an insertion sort
40How an insertion sort works
- Consider the event at some position (1..n)
- Compare it to all the events before that position
backwardstowards 0. - If the comparison event time is LESS THAN the
considered event time, then shift the comparison
event down to make room. - Wherever we stop, thats where the considered
event goes. - Consider the next eventuntil done
41InsertionSort
Trace this out to convince yourself it works!
- public void sort()
- // Perform an insertion sort
-
- // For comparing to elements at smaller
indices - SimEvent considered null
- SimEvent compareEvent null // Just for use
in loop - // Smaller index we're comparing to
- int compare
-
- // Start out assuming that position 0 is
"sorted" - // When position1, compare elements at
indices 0 and 1 - // When position2, compare at indices 0, 1,
and 2, etc. - for (int position1 position lt
elements.size() position) - considered (SimEvent) elements.get(positio
n) - // Now, we look at "considered" versus the
elements - // less than "compare"
- compare position
-
-
- // While the considered event is greater than the
compared event , - // it's in the wrong place, so move the
elements up one. - compareEvent (SimEvent)
elements.get(compare-1) - while (compareEvent.getTime() gt
- considered.getTime())
- elements.set(compare,elements.get(compare-
1)) - compare compare-1
- // If we get to the end of the array,
stop - if (compare lt 0) break
- // else get ready for the next time
through the loop - else compareEvent (SimEvent)
elements.get(compare-1) -
- // Wherever we stopped, this is where
"considered" belongs - elements.set(compare,considered)
- // for all positions 1 to the end
- // end of sort()
42Useful Links on Sorting
- http//ciips.ee.uwa.edu.au/morris/Year2/PLDS210/s
orting.html - http//www.cs.ubc.ca/spider/harrison/Java/sorting-
demo.html - http//www.cs.brockport.edu/cs/java/apps/sorters/i
nsertsort.html
Recommended
These include animations that help to see how
its all working
43Option 2 Put it in the right place
- /
- Add the event.
- The Queue MUST remain in order, from lowest
time to highest. - /
- public void add(SimEvent myEvent)
- // Option one Add then sort
- //elements.add(myEvent)
- //this.sort()
- //Option two Insert into order
- this.insertInOrder(myEvent)
-
44insertInOrder()
Again, trace it out to convince yourself that it
works!
- /
- Put thisEvent into elements, assuming
- that it's already in order.
- /
- public void insertInOrder(SimEvent thisEvent)
- SimEvent comparison null
-
- // Have we inserted yet?
- boolean inserted false
- for (int i0 i lt elements.size() i)
- comparison (SimEvent) elements.get(i)
-
-
- // Assume elements from 0..i are less than
thisEvent - // If the element time is GREATER, insert
here and - // shift the rest down
- if (thisEvent.getTime() lt
comparison.getTime()) - //Insert it here
- inserted true
- elements.add(i,thisEvent)
- break // We can stop the search loop
-
- // end for
-
- // Did we get through the list without
finding something - // greater? Must be greater than any
currently there! - if (!inserted)
- // Insert it at the end
- elements.addLast(thisEvent)
-
45Finally A Discrete Event Simulation
- Now, we can assemble queues, different kinds of
random, and a sorted EventQueue to create a
discrete event simulation.
46Running a DESimulation
- Welcome to DrJava.
- gt FactorySimulation fs new FactorySimulation()
- gt fs.openFrames("D/temp/")
- gt fs.run(25.0)
47What we see (not much)
48The detail tells the story
- Time 1.7078547183397625 Distributor 0 Arrived
at warehouse - Time 1.7078547183397625 Distributor 0 is
blocking - gtgtgt Timestep 1
- Time 1.727166341118611 Distributor 3 Arrived
at warehouse - Time 1.727166341118611 Distributor 3 is
blocking - gtgtgt Timestep 1
- Time 1.8778754913001443 Distributor 4 Arrived
at warehouse - Time 1.8778754913001443 Distributor 4 is
blocking - gtgtgt Timestep 1
- Time 1.889475045031698 Distributor 2 Arrived
at warehouse - Time 1.889475045031698 Distributor 2 is
blocking - gtgtgt Timestep 1
- Time 3.064560375192933 Distributor 1 Arrived
at warehouse - Time 3.064560375192933 Distributor 1 is
blocking - gtgtgt Timestep 3
- Time 3.444420374970288 Truck 2 Arrived at
warehouse with load 13 - Time 3.444420374970288 Distributor 0
unblocked! - Time 3.444420374970288 Distributor 0 Gathered
product for orders of 11 - gtgtgt Timestep 3
Notice that time 2 never occurs!
49What questions we can answer
- How long do distributors wait?
- Subtract the time that they unblock from the time
that they block - How much product sits in the warehouse?
- At each time a distributor leaves, figure out how
much is left in the warehouse. - How long does the line get at the warehouse?
- At each block, count the size of the queue.
- Can we move more product by having more
distributors or more trucks? - Try it!
50How DESimulation works
51FactorySimulation Extend a few classes
52DESimulation Sets the Stage
- DESimulation calls setUp to create agents and
schedule the first events. - It provides log for writing things out to the
console and a text file. - When it run()s, it processes each event in the
event queue and tells the corresponding agent to
process a particular message.
53What a DESimulation does
- // While we're not yet at the stop time,
- // and there are more events to process
- while ((now lt stopTime) (!events.empty()))
- topEvent events.pop()
-
- // Whatever event is next, that time is now
- now topEvent.getTime()
- // Let the agent now that its event has
occurred - topAgent topEvent.getAgent()
- topAgent.processEvent(topEvent.getMessage())
-
- // repaint the world to show the movement
- // IF there is a world
- if (world ! null)
- world.repaint()
-
- // Do the end of step processing
- this.endStep((int) now)
-
As long as there are events in the queue, and
were not at the stopTime Grab an event. Make
its time now Process the event.
54Whats an Event (SimEvent)?
- /
- SimulationEvent (SimEvent) -- an event that
occurs in a simulation, - like a truck arriving at a factory, or a
salesperson leaving the - market
- /
- public class SimEvent
- /// Fields ///
- / When does this event occur? /
- public double time
-
- / To whom does it occur? Who should be
informed when it occurred? / - public DEAgent whom
-
- / What is the event? We'll use integers to
represent the meaning - of the event -- the "message" of the event.
- Each agent will know the meaning of the
integer for themselves. - /
- public int message
Its a time, an Agent, and an integer that the
Agent will understand as a message
55DEAgent Process events, block if needed
- DEAgents define the constants for messages What
will be the main events for this agent? - If the agent needs a resource, it asks to see if
its available, and if not, it blocks itself. - It will be told to unblock when its ready.
- Agents are responsible for scheduling their OWN
next event!
56An Example A Truck
- /
- Truck -- delivers product from Factory
- to Warehouse.
- /
- public class Truck extends DEAgent
-
- /////// Constants for Messages
- public static final int FACTORY_ARRIVE 0
- public static final int WAREHOUSE_ARRIVE 1
-
- ////// Fields /////
- /
- Amount of product being carried
- /
- public int load
57How Trucks start
- /
- Set up the truck
- Start out at the factory
- /
- public void init(Simulation thisSim)
- // Do the default init
- super.init(thisSim)
- this.setPenDown(false) // Pen up
- this.setBodyColor(Color.green) // Let green
deliver! -
- // Show the truck at the factory
- this.moveTo(30,350)
- // Load up at the factory, and set off for
the warehouse - load this.newLoad()
- ((DESimulation) thisSim).addEvent(
- new SimEvent(this,tripTime(),WAREHOU
SE_ARRIVE)) -
The truck gets a load, then schedules itself to
arrive at the Warehouse.
58tripTime() uses the normal distribution
- / A trip distance averages 3 days /
- public double tripTime()
- double delay randNumGen.nextGaussian()3
- if (delay lt 1)
- // Must take at least one day
- return 1.0((DESimulation)
simulation).getTime() - else return delay((DESimulation)
simulation).getTime() -
59newLoad() uses uniform
- / A new load is between 10 and 20 on a uniform
distribution / - public int newLoad()
- return 10randNumGen.nextInt(11)
-
60How a Truck processes Events
- /
- Process an event.
- Default is to do nothing with it.
- /
- public void processEvent(int message)
- switch(message)
- case FACTORY_ARRIVE
- // Show the truck at the factory
- ((DESimulation) simulation).log(this.getNa
me()"\t Arrived at factory") - this.moveTo(30,350)
- // Load up at the factory, and set off
for the warehouse - load this.newLoad()
- ((DESimulation) simulation).addEvent(
- new SimEvent(this,tripTime(),WAREHOU
SE_ARRIVE)) - break
61Truck Arriving at the Warehouse
- case WAREHOUSE_ARRIVE
- // Show the truck at the warehouse
- ((DESimulation) simulation).log(this.getNa
me()"\t Arrived at warehouse with load
\t"load) - this.moveTo(50,50)
- // Unload product -- takes zero time
(unrealistic!) - ((FactorySimulation) simulation).getProduc
t().add(load) - load 0
- // Head back to factory
- ((DESimulation) simulation).addEvent(
- new SimEvent(this,tripTime(),FACTORY
_ARRIVE)) - break
62What Resources do
- They keep track of what amount they have
available (of whatever the resource is). - They keep a queue of agents that are blocked on
this resource. - They can add to the resource, or have it
consume(d). - When more resource comes in, the head of the
queue gets asked if its enough. If so, it can
unblock.
63How Resources alert agents
- /
- Add more produced resource.
- Is there enough to unblock the first
- Agent in the Queue?
- /
- public void add(int production)
- amount amount production
-
- if (!blocked.empty())
- // Ask the next Agent in the queue if it
can be unblocked - DEAgent topOne (DEAgent) blocked.peek()
- // Is it ready to run given this resource?
- if (topOne.isReady(this))
- // Remove it from the queue
- topOne (DEAgent) blocked.pop()
- // And tell it its unblocked
- topOne.unblocked(this)
-
-
64An example blocking agent Distributor
- /
- Distributor -- takes orders from Market to
Warehouse, - fills them, and returns with product.
- /
- public class Distributor extends DEAgent
-
- /////// Constants for Messages
- public static final int MARKET_ARRIVE 0
- public static final int MARKET_LEAVE 1
- public static final int WAREHOUSE_ARRIVE 2
-
- / AmountOrdered so-far /
- int amountOrdered
65Distributors start in the Market
- public void init(Simulation thisSim)
- //First, do the normal stuff
- super.init(thisSim)
- this.setPenDown(false) // Pen up
- this.setBodyColor(Color.blue) // Go Blue!
-
- // Show the distributor in the market
- this.moveTo(600,460) // At far right
- // Get the orders, and set off for the
warehouse - amountOrdered this.newOrders()
- ((DESimulation) thisSim).addEvent(
- new SimEvent(this,tripTime(),WAREHOU
SE_ARRIVE)) -
66Distributors have 3 events
- Arrive in Market Schedule how long itll take to
deliver. - Leave Market Schedule arrive at the Factory
- Arrive at Warehouse Is there enough product
available? If not, block and wait for trucks to
bring enough product.
67Processing Distributor Events
- /
- Process an event.
- Default is to do nothing with it.
- /
- public void processEvent(int message)
- switch(message)
- case MARKET_ARRIVE
- // Show the distributor at the market,
far left - ((DESimulation) simulation).log(this.get
Name()"\t Arrived at market") - this.moveTo(210,460)
- // Schedule time to deliver
- ((DESimulation) simulation).addEvent(
- new SimEvent(this,timeToDeliver(),MA
RKET_LEAVE)) - break
68Leaving the Market
- case MARKET_LEAVE
- // Show the distributor at the market,
far right - ((DESimulation) simulation).log(this.get
Name()"\t Leaving market") - this.moveTo(600,460)
- // Get the orders, and set off for the
warehouse - amountOrdered this.newOrders()
- ((DESimulation) simulation).addEvent(
- new SimEvent(this,tripTime(),WAREHOU
SE_ARRIVE)) - break
69Arriving at the Warehouse
- case WAREHOUSE_ARRIVE
- // Show the distributor at the
warehouse - ((DESimulation) simulation).log(this.get
Name()"\t Arrived at warehouse") - this.moveTo(600,50)
- // Is there enough product available?
- Resource warehouseProduct
((FactorySimulation) simulation).getProduct() - if (warehouseProduct.amountAvailable()
gt amountOrdered) -
- // Consume the resource for the
orders - warehouseProduct.consume(amountOrdered
) // Zero time to load? - ((DESimulation) simulation).log(this.g
etName()"\t Gathered product for orders of
\t"amountOrdered) - // Schedule myself to arrive at the
Market - ((DESimulation) simulation).addEvent(
- new SimEvent(this,tripTime(),MA
RKET_ARRIVE)) -
- else // We have to wait until more
product arrives! - ((DESimulation) simulation).log(this.g
etName()"\t is blocking") - waitFor(((FactorySimulation)
simulation).getProduct()) - break
70Is there enough product?
- / Are we ready to be unlocked? /
- public boolean isReady(Resource res)
- // Is the amount in the factory more than our
orders? - return ((FactorySimulation)
simulation).getProduct().amountAvailable() gt
amountOrdered -
71If so, well be unblocked
- /
- I've been unblocked!
- _at_param resource the desired resource
- /
- public void unblocked(Resource resource)
- super.unblocked(resource)
-
- // Consume the resource for the orders
- ((DESimulation) simulation).log(this.getName()
"\t unblocked!") - resource.consume(amountOrdered) // Zero time
to load? - ((DESimulation) simulation).log(this.getName()
"\t Gathered product for orders of
\t"amountOrdered) - // Schedule myself to arrive at the Market
- ((DESimulation) simulation).addEvent(
- new SimEvent(this,tripTime(),MARKET_
ARRIVE)) -
72The Overall Factory Simulation
- /
- FactorySimulation -- set up the whole
simulation, - including creation of the Trucks and
Distributors. - /
- public class FactorySimulation extends
DESimulation -
- private Resource product
-
- /
- Accessor for factory
- /
- public FactoryProduct getFactory()return
factory -
73Setting up the Factory Simulation
- public void setUp()
- // Let the world be setup
- super.setUp()
- // Give the world a reasonable background
- FileChooser.setMediaPath("D/cs1316/MediaSourc
es/") - world.setPicture(new Picture(
- FileChooser.getMediaPath("Econo
myBackground.jpg"))) -
- // Create a warehouse resource
- product new Resource() //Track product
-
- // Create three trucks
- Truck myTruck null
- for (int i0 ilt3 i)
- myTruck new Truck(world,this)
- myTruck.setName("Truck "i)
- // Create five Distributors
- Distributor sales null
74The Master Data Structure ListWe use almost
everything here!
- Queues For storing the agents waiting in line.
- EventQueues For storing the events scheduled to
occur. - LinkedList For storing all the agents.