Java Reference
In-Depth Information
The following sequence of events occurs when the code executes:
1.
Assuming the
Consumer
thread runs first (which is only an assumption and not a guar-
antee), its
run
method is invoked.
2.
On line 10, the thread attempts to acquire the monitor lock of the stack. Again, let's
assume the lock is available.
3.
The
Consumer
pops an
int
off the stack. With our assumptions so far, the value
returned is
-1
because the
Producer
has not had a chance to push anything onto the
stack yet.
4.
The
Consumer
calls
wait
on line 15 and gives up the monitor lock of the stack.
5.
The
Producer
thread is started and its
run
method is invoked. A random
int
between
0
and
4
is pushed onto the stack on line 12.
6.
On line 14, the
Producer
thread attempts to acquire the lock of the stack. This step is
necessary because the call to
notify
can only occur if the thread owns the lock on the
stack.
7.
On line 16, the
notify
method awakens the
Consumer
thread and its state changes
from
WAITING
to
BLOCKED
. Notice the
Consumer
thread is not
RUNNABLE
at this point
in time. Why? Because the
Producer
thread still has the lock on the stack and the
Consumer
thread was within synchronized code when it invoked
wait
.
8.
The
Producer
thread gives up the lock of the
MyStack2
object on line 17, causing the
Consumer
thread to transition to the
RUNNABLE
state.
9.
The
Producer
thread sleeps, allowing the
Consumer
thread to obtain the lock of the
stack and pop the recently pushed value. The stack is now empty because the
Producer
is sleeping, so the
Consumer
waits again.
This process repeats indefi nitely because the threads run in infi nite
while
loops.
The output changes each time because we are dealing with threads and also because the
numbers pushed onto the stack are random. Here is a typical output of the code:
Waiting...
Just pushed 1
Notifying...
Just popped 1
Waiting...
Just pushed 3
Notifying...
Just popped 3
Waiting...
Just pushed 4
Notifying...
Just popped 4
Waiting...
Search WWH ::
Custom Search