epubjs
Version:
Render ePub documents in the browser, across many devices
421 lines (405 loc) • 56.2 kB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Synchronization</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Synchronization"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-9-SECT-3"/>Synchronization</h1></div></div></div><p><a id="I_indexterm9_id716144" class="indexterm"/>Every thread has a mind of its own. Normally, a thread goes
about its business without any regard for what other threads in the
application are doing. Threads may be time-sliced, which means they can
run in arbitrary spurts and bursts as directed by the operating system. On
a multiprocessor system, it is even possible for many different threads to
be running simultaneously on different CPUs. This section is about
coordinating the activities of two or more threads so that they can work
together and not collide in their use of the same variables and methods
(coordinating their play on the golf course).</p><p>Java provides a few simple structures for synchronizing the
activities of threads. They are all based on the concept of monitors, a
widely used synchronization scheme. You don’t have to know the details
about how monitors work to be able to use them, but it may help you to
have a picture in mind.</p><p><a id="I_indexterm9_id716164" class="indexterm"/>A monitor is essentially a lock. The lock is attached to a
resource that many threads may need to access, but that should be accessed
by only one thread at a time. It’s very much like a restroom with a lock
on the door; if it’s unlocked, you can enter and lock the door while you
are using it. If the resource is not being used, the thread can acquire
the lock and access the resource. When the thread is done, it relinquishes
the lock, just as you unlock the restroom door and leave it open for the
next person. However, if another thread already has the lock for the
resource, all other threads must wait until the current thread is done and
has released the lock. This is just like when the restroom is occupied
when you arrive: you have to wait until the current user is done and
unlocks the door.</p><p>Fortunately, Java makes the process of synchronizing access to
resources fairly easy. The language handles setting up and acquiring
locks; all you need to do is specify the resources that require
synchronization.</p><div class="sect2" title="Serializing Access to Methods"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-3.1"/>Serializing Access to Methods</h2></div></div></div><p><a id="I_indexterm9_id716190" class="indexterm"/> <a id="idx10502" class="indexterm"/>The most common need for synchronization among threads in
Java is to serialize their access to some resource (an object)—in other
words, to make sure that only one thread at a time can manipulate an
object or variable.<sup>[<a id="learnjava3-CHP-9-FNOTE-2" href="#ftn.learnjava3-CHP-9-FNOTE-2" class="footnote">26</a>]</sup> In Java, every object has an associated lock. To be more
specific, every class and every instance of a class has its own lock.
The <a id="I_indexterm9_id716236" class="indexterm"/><code class="literal">synchronized</code> keyword
marks places where a thread must acquire the lock before proceeding.</p><p>For example, suppose we implemented a <code class="literal">SpeechSynthesizer</code> class that contains a
<code class="literal">say()</code> method. We don’t want multiple
threads calling <code class="literal">say()</code> at the same
time because we wouldn’t be able to understand anything being said. So
we mark the <code class="literal">say()</code> method as <code class="literal">synchronized</code>, which means that a thread must
acquire the lock on the <code class="literal">SpeechSynthesizer</code> object before it can
speak:</p><a id="I_9_tt499"/><pre class="programlisting"> <code class="kd">class</code> <code class="nc">SpeechSynthesizer</code> <code class="o">{</code>
<code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">say</code><code class="o">(</code> <code class="n">String</code> <code class="n">words</code> <code class="o">)</code> <code class="o">{</code>
<code class="c1">// speak</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>Because <code class="literal">say()</code> is an instance
method, a thread must acquire the lock on the <code class="literal">SpeechSynthesizer</code> instance it’s using before
it can invoke the <code class="literal">say()</code> method. When
<code class="literal">say()</code> has completed, it gives up the
lock, which allows the next waiting thread to acquire the lock and run
the method. It doesn’t matter whether the thread is owned by the
<code class="literal">SpeechSynthesizer</code> itself or some
other object; every thread must acquire the same lock, that of the
<code class="literal">SpeechSynthesizer</code> instance. If
<code class="literal">say()</code> were a class (static) method
instead of an instance method, we could still mark it as <code class="literal">synchronized</code>. In this case, because no
instance object is involved, the lock is on the class object
itself.</p><p>Often, you want to synchronize multiple methods of the same class
so that only one method modifies or examines parts of the class at a
time. All static synchronized methods in a class use the same class
object lock. By the same token, all instance methods in a class use the
same instance object lock. In this way, Java can guarantee that only one
of a set of synchronized methods is running at a time. For example, a
<code class="literal">SpreadSheet</code> class might contain a
number of instance variables that represent cell values as well as some
methods that manipulate the cells in a row:</p><a id="I_9_tt500"/><pre class="programlisting"> <code class="kd">class</code> <code class="nc">SpreadSheet</code> <code class="o">{</code>
<code class="kt">int</code> <code class="n">cellA1</code><code class="o">,</code> <code class="n">cellA2</code><code class="o">,</code> <code class="n">cellA3</code><code class="o">;</code>
<code class="kd">synchronized</code> <code class="kt">int</code> <code class="nf">sumRow</code><code class="o">()</code> <code class="o">{</code>
<code class="k">return</code> <code class="n">cellA1</code> <code class="o">+</code> <code class="n">cellA2</code> <code class="o">+</code> <code class="n">cellA3</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">setRow</code><code class="o">(</code> <code class="kt">int</code> <code class="n">a1</code><code class="o">,</code> <code class="kt">int</code> <code class="n">a2</code><code class="o">,</code> <code class="kt">int</code> <code class="n">a3</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">cellA1</code> <code class="o">=</code> <code class="n">a1</code><code class="o">;</code>
<code class="n">cellA2</code> <code class="o">=</code> <code class="n">a2</code><code class="o">;</code>
<code class="n">cellA3</code> <code class="o">=</code> <code class="n">a3</code><code class="o">;</code>
<code class="o">}</code>
<code class="o">...</code>
<code class="o">}</code></pre><p>In this example, methods <code class="literal">setRow()</code> and <code class="literal">sumRow()</code> both access the cell values. You can
see that problems might arise if one thread were changing the values of
the variables in <code class="literal">setRow()</code> at the same
moment another thread was reading the values in <code class="literal">sumRow()</code>. To prevent this, we have marked both
methods as <code class="literal">synchronized</code>. When threads
are synchronized, only one runs at a time. If a thread is in the middle
of executing <code class="literal">setRow()</code> when another
thread calls <code class="literal">sumRow()</code>, the second
thread waits until the first one finishes executing <code class="literal">setRow()</code> before it runs <code class="literal">sumRow()</code>. This synchronization allows us to
preserve the consistency of the <code class="literal">SpreadSheet</code>. The best part is that all this
locking and waiting is handled by Java; it’s invisible to the
programmer.</p><p>In addition to synchronizing entire methods, the <a id="I_indexterm9_id716443" class="indexterm"/><code class="literal">synchronized</code> keyword
can be used in a special construct to guard arbitrary blocks of code. In
this form, it also takes an explicit argument that specifies the object
for which it is to acquire a lock:</p><a id="I_9_tt501"/><pre class="programlisting"> <code class="kd">synchronized</code> <code class="o">(</code> <code class="n">myObject</code> <code class="o">)</code> <code class="o">{</code>
<code class="c1">// Functionality that needs exclusive access to resources</code>
<code class="o">}</code></pre><p>This code block can appear in any method. When it is reached, the
thread has to acquire the lock on <code class="literal">myObject</code> before proceeding. In this way, we
can synchronize methods (or parts of methods) in different classes in
the same way as methods in the same class.</p><p>A synchronized instance method is, therefore, equivalent to a
method with its statements synchronized on the current object.
Thus:</p><a id="I_9_tt502"/><pre class="programlisting"> <code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">myMethod</code> <code class="o">()</code> <code class="o">{</code>
<code class="o">...</code>
<code class="o">}</code></pre><p>is equivalent to:<a id="I_indexterm9_id716489" class="indexterm"/></p><a id="I_9_tt503"/><pre class="programlisting"> <code class="kt">void</code> <code class="nf">myMethod</code> <code class="o">()</code> <code class="o">{</code>
<code class="kd">synchronized</code> <code class="o">(</code> <code class="k">this</code> <code class="o">)</code> <code class="o">{</code>
<code class="o">...</code>
<code class="o">}</code>
<code class="o">}</code></pre></div><div class="sect2" title="Accessing class and instance Variables from Multiple Threads"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-3.2"/>Accessing class and instance Variables from Multiple
Threads</h2></div></div></div><p><a id="I_indexterm9_id716512" class="indexterm"/>In the <code class="literal">SpreadSheet</code>
example, we guarded access to a set of instance variables with a
synchronized method in order to avoid changing one of the variables
while someone was reading the others. We wanted to keep them
coordinated. But what about individual variable types? Do they need to
be synchronized? Normally, the answer is no. Almost all operations on
primitives and object reference types in Java happen
<span class="emphasis"><em>atomically</em></span>: that is, they are handled by the VM in
one step, with no opportunity for two threads to collide. This prevents
threads from looking at references while they are in the process of
being accessed by other threads.</p><p>But watch out—we did say <span class="emphasis"><em>almost</em></span>. If you read
the Java VM specification carefully, you will see that the <a id="I_indexterm9_id716544" class="indexterm"/><code class="literal">double</code> and <a id="I_indexterm9_id716558" class="indexterm"/><code class="literal">long</code> primitive types
are not guaranteed to be handled atomically. Both of these types
represent 64-bit values. The problem has to do with how the Java VM’s
stack handles them. It is possible that this specification will be
beefed up in the future. But for now, to be strict, you should
synchronize access to your <code class="literal">double</code> and
<code class="literal">long</code> instance variables through
accessor methods, or use the <a id="I_indexterm9_id716587" class="indexterm"/><code class="literal">volatile</code> keyword or an
atomic wrapper class, which we’ll describe next.</p><p>Another issue, independent of the atomicity of the values, is the
notion of different threads in the VM caching values for periods of
time—that is, even though one thread may have changed the value, the
Java VM may not be obliged to make that value appear until the VM
reaches a certain state known as a “memory barrier.” While this should
not be a problem in most real-world programming cases, you can address
this by declaring the variable with the <code class="literal">volatile</code> keyword. This keyword indicates to
the VM that the value may be changed by external threads and effectively
synchronizes access to it automatically.</p><p>Finally, the <a id="I_indexterm9_id716618" class="indexterm"/><code class="literal">java.util.concurrent.atomic</code> package provides
synchronized wrapper classes for all primitive types and references.
These wrappers provide not only simple <code class="literal">set()</code> and <code class="literal">get()</code> operations on the values but also
specialized “combo” operations, such as <a id="I_indexterm9_id716642" class="indexterm"/><code class="literal">compareAndSet()</code>, that
work atomically and can be used to build higher-level synchronized
application components. The classes in this package were designed
specifically to map down to hardware-level functionality in many cases
and can be very efficient. We’ll talk more about them later in this
chapter.</p><div class="sect3" title="Reentrant locking"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-9-SECT-3.2.2"/>Reentrant locking</h3></div></div></div><p><a id="I_indexterm9_id716665" class="indexterm"/>The locks acquired by Java upon entering a synchronized
method or block of code are <span class="emphasis"><em>reentrant</em></span>, meaning
that the thread holding onto the lock may acquire the same lock again
any number of times and never blocks waiting for itself. In most
cases, this means that the code behaves as you’d expect; a thread can
call a synchronized method recursively and can itself call upon other
synchronized methods within the same object.</p></div></div><div class="sect2" title="The wait() and notify() Methods"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-3.3"/>The wait() and notify() Methods</h2></div></div></div><p><a id="idx10476" class="indexterm"/> <a id="idx10500" class="indexterm"/> <a id="idx10504" class="indexterm"/> <a id="idx10511" class="indexterm"/>With the <code class="literal">synchronized</code>
keyword, we can serialize the execution of methods and blocks of code so
that only one thread at a time can execute a synchronized item. The
<code class="literal">wait()</code> and <code class="literal">notify()</code> methods of the <a id="I_indexterm9_id716757" class="indexterm"/><code class="literal">Object</code> class extend
this capability by allowing us to explicitly coordinate the waiting and
running threads. Every object in Java is a subclass of <code class="literal">Object</code>, so every object inherits these
methods. By using <code class="literal">wait()</code> and <code class="literal">notify()</code>, a thread can effectively give up its
hold on a lock at an arbitrary point and then wait for another thread to
give it back before continuing. All of the coordinated activity still
happens inside synchronized blocks, and still only one thread is
executing at a given time.</p><p>By executing <code class="literal">wait()</code> from a
synchronized block, a thread gives up its hold on the lock and goes to
sleep. A thread might do this if it needs to wait for something to
happen in another part of the application, as we’ll see shortly. Later,
when the necessary event happens, the running thread calls <code class="literal">notify()</code> from a block synchronized on the same
object. The first thread wakes up and begins trying to acquire the lock
again. When the first thread manages to reacquire the lock, it continues
from where it left off. However, the thread that was waiting may not get
the lock immediately (or perhaps ever). It depends on when the second
thread eventually releases the lock and which thread manages to snag it
next. The first thread won’t wake up from the <code class="literal">wait()</code> unless another thread calls <code class="literal">notify()</code>. An overloaded version of <code class="literal">wait()</code>, however, allows us to specify a
timeout period. If another thread doesn’t call <code class="literal">notify()</code> in the specified period, the waiting
thread automatically wakes up.</p><p>Let’s look at a simple scenario to see what’s going on. In the
following example, we’ll assume there are three threads—one waiting to
execute each of the three synchronized methods of the <code class="literal">MyThing</code> class. We’ll call them the
<span class="emphasis"><em>waiter</em></span>, <span class="emphasis"><em>notifier</em></span>, and
<span class="emphasis"><em>related</em></span> threads. Here’s a code fragment to
illustrate:</p><a id="I_9_tt504"/><pre class="programlisting"> <code class="kd">class</code> <code class="nc">MyThing</code> <code class="o">{</code>
<code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">waiterMethod</code><code class="o">()</code> <code class="o">{</code>
<code class="c1">// do some stuff</code>
<code class="n">wait</code><code class="o">();</code> <code class="c1">// now wait for notifier to do something</code>
<code class="c1">// continue where we left off</code>
<code class="o">}</code>
<code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">notifierMethod</code><code class="o">()</code> <code class="o">{</code>
<code class="c1">// do some stuff</code>
<code class="n">notify</code><code class="o">();</code> <code class="c1">// notify waiter that we've done it</code>
<code class="c1">// continue doing stuff</code>
<code class="o">}</code>
<code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">relatedMethod</code><code class="o">()</code> <code class="o">{</code>
<code class="c1">// do some related stuff</code>
<code class="o">}</code>
<code class="o">...</code>
<code class="o">}</code></pre><p>Let’s assume that a thread named <span class="emphasis"><em>waiter</em></span> gets
through the gate first and begins executing <code class="literal">waiterMethod()</code>. The two other threads are
initially blocked when trying to acquire the lock for the <code class="literal">MyThing</code> object. When
<span class="emphasis"><em>waiter</em></span> executes the <code class="literal">wait()</code> method, it relinquishes its hold on the
lock and goes to sleep. Now two viable threads are waiting for the lock.
Which thread gets it depends on several factors, including chance and
the priorities of the threads. (We’ll discuss thread scheduling in the
next section.)</p><p>Let’s suppose that <span class="emphasis"><em>notifier</em></span> is the next
thread to acquire the lock, so it begins to run <code class="literal">notifierMethod()</code>. <span class="emphasis"><em>waiter</em></span>
continues to sleep, and <span class="emphasis"><em>related</em></span> languishes, waiting
for its turn. When <span class="emphasis"><em>notifier</em></span> executes the call to
<code class="literal">notify()</code>, the runtime system prods
the <span class="emphasis"><em>waiter</em></span> thread, effectively telling it something
has changed. <span class="emphasis"><em>waiter</em></span> wakes up and rejoins
<span class="emphasis"><em>related</em></span> in vying for the <code class="literal">MyThing</code> lock. It doesn’t receive the lock
automatically; it just changes its state from “Leave me alone” to “I
want the lock.”</p><p>At this point, <span class="emphasis"><em>notifier</em></span> still owns the lock
and continues to hold it until the synchronized <code class="literal">notifierMethod()</code> returns, or perhaps executes
a <code class="literal">wait()</code> itself. At that point, the
other two methods get to fight over the lock.
<span class="emphasis"><em>waiter</em></span> would like to continue executing <code class="literal">waiterMethod()</code> from the point where it left
off, while <span class="emphasis"><em>related</em></span>, which has been patient, would
like to get started. We’ll let you choose your own ending for the
story.</p><p>For each call to <code class="literal">notify()</code>, the
runtime system wakes up just one thread that is asleep in a <code class="literal">wait()</code> call. The group of threads waiting on a
lock is called the <span class="emphasis"><em>wait set</em></span>. If multiple threads
are waiting, Java picks a thread on an arbitrary basis, which may be
implementation-dependent. The <a id="I_indexterm9_id717005" class="indexterm"/><code class="literal">Object</code> class also
provides a <code class="literal">notifyAll()</code> call to wake
up all waiting threads. In most cases, you’ll probably want to use
<code class="literal">notifyAll()</code> rather than <code class="literal">notify()</code>. Keep in mind that <code class="literal">notify()</code> really means, “Hey, something related
to this object has changed. The condition you are waiting for may have
changed, so check it again.” In general, there is no reason to assume
only one thread at a time is interested in the change or able to act
upon it. Different threads might look upon whatever has changed in
different ways.</p><div class="sect3" title="Wait conditions"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-9-SECT-3.3.1"/>Wait conditions</h3></div></div></div><p>In general, our <span class="emphasis"><em>waiter</em></span> thread is waiting
for a particular condition to change, and we will want it to sit in a
loop like the following:</p><a id="I_9_tt505"/><pre class="programlisting"> <code class="k">while</code> <code class="o">(</code> <code class="n">condition</code> <code class="o">!=</code> <code class="kc">true</code> <code class="o">)</code>
<code class="n">wait</code><code class="o">();</code></pre><p>This test is called the <span class="emphasis"><em>wait condition</em></span>.
Other synchronized threads call <code class="literal">notify()</code> or <a id="I_indexterm9_id717079" class="indexterm"/><code class="literal">notifyAll()</code> when they
have modified the environment so that the condition can be checked
again. It’s important to use a loop on the wait condition to be sure
that the thread has been awakened for the right reason. Threads may
also use a timed version of <code class="literal">wait()</code>
to do periodic work while checking the condition in this way. Using
wait conditions like this is also an alternative to polling and
sleeping, as you’ll see in the following section.<a id="I_indexterm9_id717103" class="indexterm"/><a id="I_indexterm9_id717110" class="indexterm"/><a id="I_indexterm9_id717117" class="indexterm"/><a id="I_indexterm9_id717124" class="indexterm"/></p></div></div><div class="sect2" title="Passing Messages"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-3.4"/>Passing Messages</h2></div></div></div><p><a id="idx10501" class="indexterm"/>We’ll next illustrate a classic interaction between two
threads: a <code class="literal">Producer</code> and a <code class="literal">Consumer</code>. A producer thread creates messages
and places them into a queue while a consumer reads and displays them.
To be realistic, we’ll give the queue a maximum depth. And to make
things really interesting, we’ll have our consumer thread be lazy and
run much more slowly than the producer. This means that <code class="literal">Producer</code> occasionally has to stop and wait for
<code class="literal">Consumer</code> to catch up. The Java
concurrency package has a <a id="I_indexterm9_id717182" class="indexterm"/><code class="literal">BlockingQueue</code> interface
that provides exactly this kind of functionality, but we’ll build it
ourselves here using basic synchronization techniques first and then
take a look at <code class="literal">Queue</code>s and all of the
collection classes in <a class="xref" href="ch11.html" title="Chapter 11. Core Utilities">Chapter 11</a>.</p><p>Here are the <code class="literal">Producer</code> and
<code class="literal">Consumer</code> classes:</p><a id="I_9_tt506"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.util.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">Consumer</code> <code class="kd">implements</code> <code class="n">Runnable</code> <code class="o">{</code>
<code class="n">Producer</code> <code class="n">producer</code><code class="o">;</code>
<code class="n">Consumer</code><code class="o">(</code> <code class="n">Producer</code> <code class="n">producer</code> <code class="o">)</code> <code class="o">{</code>
<code class="k">this</code><code class="o">.</code><code class="na">producer</code> <code class="o">=</code> <code class="n">producer</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">run</code><code class="o">()</code> <code class="o">{</code>
<code class="k">while</code> <code class="o">(</code> <code class="kc">true</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">String</code> <code class="n">message</code> <code class="o">=</code> <code class="n">producer</code><code class="o">.</code><code class="na">getMessage</code><code class="o">();</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Got message: "</code> <code class="o">+</code> <code class="n">message</code><code class="o">);</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">Thread</code><code class="o">.</code><code class="na">sleep</code><code class="o">(</code> <code class="mi">2000</code> <code class="o">);</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">InterruptedException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">}</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code> <code class="n">args</code><code class="o">[])</code> <code class="o">{</code>
<code class="n">Producer</code> <code class="n">producer</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Producer</code><code class="o">();</code>
<code class="k">new</code> <code class="nf">Thread</code><code class="o">(</code> <code class="n">producer</code> <code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="n">Consumer</code> <code class="n">consumer</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Consumer</code><code class="o">(</code> <code class="n">producer</code> <code class="o">);</code>
<code class="k">new</code> <code class="nf">Thread</code><code class="o">(</code> <code class="n">consumer</code> <code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">Producer</code> <code class="kd">implements</code> <code class="n">Runnable</code><code class="o">{</code>
<code class="kd">static</code> <code class="kd">final</code> <code class="kt">int</code> <code class="n">MAXQUEUE</code> <code class="o">=</code> <code class="mi">5</code><code class="o">;</code>
<code class="kd">private</code> <code class="n">List</code> <code class="n">messages</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ArrayList</code><code class="o">();</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">run</code><code class="o">()</code> <code class="o">{</code>
<code class="k">while</code> <code class="o">(</code> <code class="kc">true</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">putMessage</code><code class="o">();</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">Thread</code><code class="o">.</code><code class="na">sleep</code><code class="o">(</code> <code class="mi">1000</code> <code class="o">);</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">InterruptedException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">}</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="c1">// called by Producer internally</code>
<code class="kd">private</code> <code class="kd">synchronized</code> <code class="kt">void</code> <code class="nf">putMessage</code><code class="o">()</code>
<code class="o">{</code>
<code class="k">while</code> <code class="o">(</code> <code class="n">messages</code><code class="o">.</code><code class="na">size</code><code class="o">()</code> <code class="o">>=</code> <code class="n">MAXQUEUE</code> <code class="o">)</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">wait</code><code class="o">();</code>
<code class="o">}</code> <code class="k">catch</code><code class="o">(</code> <code class="n">InterruptedException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">}</code>
<code class="n">messages</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="k">new</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">Date</code><code class="o">().</code><code class="na">toString</code><code class="o">()</code> <code class="o">);</code>
<code class="n">notify</code><code class="o">();</code>
<code class="o">}</code>
<code class="c1">// called by Consumer externally</code>
<code class="kd">public</code> <code class="kd">synchronized</code> <code class="n">String</code> <code class="nf">getMessage</code><code class="o">()</code>
<code class="o">{</code>
<code class="k">while</code> <code class="o">(</code> <code class="n">messages</code><code class="o">.</code><code class="na">size</code><code class="o">()</code> <code class="o">==</code> <code class="mi">0</code> <code class="o">)</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">notify</code><code class="o">();</code>
<code class="n">wait</code><code class="o">();</code>
<code class="o">}</code> <code class="k">catch</code><code class="o">(</code> <code class="n">InterruptedException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">}</code>
<code class="n">String</code> <code class="n">message</code> <code class="o">=</code> <code class="o">(</code><code class="n">String</code><code class="o">)</code><code class="n">messages</code><code class="o">.</code><code class="na">remove</code><code class="o">(</code><code class="mi">0</code><code class="o">);</code>
<code class="n">notify</code><code class="o">();</code>
<code class="k">return</code> <code class="n">message</code><code class="o">;</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>For convenience, we have included a <code class="literal">main()</code> method in the <code class="literal">Consumer</code> class that runs the complete example.
It creates a <code class="literal">Consumer</code> that is tied to
a <code class="literal">Producer</code> and starts the two
classes. You can run the example as follows:</p><a id="I_9_tt507"/><pre class="programlisting"> <code class="o">%</code> <strong class="userinput"><code><code class="n">java</code> <code class="n">Consumer</code></code></strong></pre><p>This produces the timestamp messages created by the <code class="literal">Producer</code>:</p><a id="I_9_tt508"/><pre class="programlisting"> <code class="n">Got</code> <code class="nl">message:</code> <code class="n">Sun</code> <code class="n">Dec</code> <code class="mi">19</code> <code class="mi">03</code><code class="o">:</code><code class="mi">35</code><code class="o">:</code><code class="mi">55</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">Got</code> <code class="nl">message:</code> <code class="n">Sun</code> <code class="n">Dec</code> <code class="mi">19</code> <code class="mi">03</code><code class="o">:</code><code class="mi">35</code><code class="o">:</code><code class="mi">56</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">Got</code> <code class="nl">message:</code> <code class="n">Sun</code> <code class="n">Dec</code> <code class="mi">19</code> <code class="mi">03</code><code class="o">:</code><code class="mi">35</code><code class="o">:</code><code class="mi">57</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="o">...</code></pre><p>The timestamps initially show a spacing of one second even though
they appear every two seconds. Our <code class="literal">Producer</code> runs faster than our <code class="literal">Consumer</code>. <code class="literal">Producer</code> would like to generate a new message
every second, while <code class="literal">Consumer</code> gets
around to reading and displaying a message only every two seconds. Can
you see how long it will take the message queue to fill up? What happens
when it does?</p><p>Let’s look at the code. We are using a few new tools here.
<code class="literal">Producer</code> and <code class="literal">Consumer</code> implement the <code class="literal">Runnable</code> interface, and each has a thread
associated with it. The <code class="literal">Producer</code> and
<code class="literal">Consumer</code> classes pass messages
through an instance of a <code class="literal">java.util.List</code> object. We haven’t discussed
the <code class="literal">List</code> class yet, but it is
essentially a dynamic array of elements. We use this one as a queue by
simply adding and removing elements in first-in, first-out order. The
<code class="literal">List</code> has no maximum capacity of its
own, but we impose one with our own check.</p><p>The important activity is in the synchronized methods: <code class="literal">putMessage()</code> and <code class="literal">getMessage()</code>. Although one of the methods is
used by the <code class="literal">Producer</code> thread and the
other by the <code class="literal">Consumer</code> thread, they
both live in the <code class="literal">Producer</code> class so
that we can coordinate them simply by declaring them <a id="I_indexterm9_id717410" class="indexterm"/><code class="literal">synchronized</code>. Here,
they both implicitly use the <code class="literal">Producer</code>
object’s lock. If the queue is empty, the <code class="literal">Consumer</code> blocks in a call in the <code class="literal">Producer</code>, waiting for another message.</p><p>Another design option would implement the <code class="literal">getMessage()</code> method in the <code class="literal">Consumer</code> class and use a <code class="literal">synchronized</code> code block to synchronize
explicitly on the <code class="literal">Producer</code> object. In
either case, synchronizing on the <code class="literal">Producer</code> enables us to have multiple <code class="literal">Consumer</code> objects that feed from the same
<code class="literal">Producer</code>. We’ll do that later in this
section.</p><p><code class="literal">putMessage()</code>’s job is to add a
new message to the queue. It can’t do this if the queue is already full,
so it first checks the number of elements in <code class="literal">messages</code>. If there is room, it stuffs in
another timestamp message. If the queue is at its limit, however,
<code class="literal">putMessage()</code> has to wait until
there’s space. In this situation, <code class="literal">putMessage()</code> executes a <code class="literal">wait()</code> and relies on the consumer to call
<code class="literal">notify()</code> to wake it up after a
message has been read. Here, we have <code class="literal">putMessage()</code> testing the condition in a loop.
In this simple example, the test might not seem necessary; we could
assume that when <code class="literal">putMessage()</code> wakes
up, there is a free spot. However, it’s important to always test our
wait condition in a loop like this when we synchronize threads because
there is no other way to be certain why our thread has been awakened.
Before it finishes, <code class="literal">putMessage()</code>
calls <code class="literal">notify()</code> itself to prod any
<code class="literal">Consumer</code> that might be waiting on an
empty queue.</p><p><code class="literal">getMessage()</code> retrieves a
message for the <code class="literal">Consumer</code>. It enters a
loop like that of <code class="literal">putMessage()</code>,
waiting for the queue to have at least one element before proceeding. If
the queue is empty, it executes a <a id="I_indexterm9_id717569" class="indexterm"/><code class="literal">wait()</code> and expects the
<code class="literal">Producer</code> to call <a id="I_indexterm9_id717585" class="indexterm"/><code class="literal">notify()</code> when more
items are available. Notice that <code class="literal">getMessage()</code> makes its own calls to <code class="literal">notify()</code>. It does this any time the queue is
empty, to prod a producer that might be sleeping and also after it
consumes a message, to give the producer the go-ahead to fill the queue
again. These scenarios are more plausible if there are more consumers,
as we’ll see next.</p><p>Let’s add another consumer to the scenario, just to make things
more interesting. Most of the necessary changes are in the <code class="literal">Consumer</code> class; here’s the code for the
modified class, now called <code class="literal">NamedConsumer</code>:</p><a id="I_9_tt509"/><pre class="programlisting"> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">NamedConsumer</code> <code class="kd">implements</code> <code class="n">Runnable</code>
<code class="o">{</code>
<code class="n">Producer</code> <code class="n">producer</code><code class="o">;</code>
<code class="n">String</code> <code class="n">name</code><code class="o">;</code>
<code class="n">NamedConsumer</code><code class="o">(</code><code class="n">String</code> <code class="n">name</code><code class="o">,</code> <code class="n">Producer</code> <code class="n">producer</code><code class="o">)</code> <code class="o">{</code>
<code class="k">this</code><code class="o">.</code><code class="na">producer</code> <code class="o">=</code> <code class="n">producer</code><code class="o">;</code>
<code class="k">this</code><code class="o">.</code><code class="na">name</code> <code class="o">=</code> <code class="n">name</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">run</code><code class="o">()</code> <code class="o">{</code>
<code class="k">while</code> <code class="o">(</code> <code class="kc">true</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">String</code> <code class="n">message</code> <code class="o">=</code> <code class="n">producer</code><code class="o">.</code><code class="na">getMessage</code><code class="o">();</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">name</code> <code class="o">+</code> <code class="s">" got message: "</code> <code class="o">+</code> <code class="n">message</code><code class="o">);</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">Thread</code><code class="o">.</code><code class="na">sleep</code><code class="o">(</code> <code class="mi">2000</code> <code class="o">);</code>
<code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">InterruptedException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">}</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code> <code class="n">args</code><code class="o">[])</code> <code class="o">{</code>
<code class="n">Producer</code> <code class="n">producer</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Producer</code><code class="o">();</code>
<code class="k">new</code> <code class="nf">Thread</code><code class="o">(</code> <code class="n">producer</code> <code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="n">NamedConsumer</code> <code class="n">consumer</code> <code class="o">=</code> <code class="k">new</code> <code class="n">NamedConsumer</code><code class="o">(</code> <code class="s">"One"</code><code class="o">,</code> <code class="n">producer</code> <code class="o">);</code>
<code class="k">new</code> <code class="nf">Thread</code><code class="o">(</code> <code class="n">consumer</code> <code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="n">consumer</code> <code class="o">=</code> <code class="k">new</code> <code class="n">NamedConsumer</code><code class="o">(</code> <code class="s">"Two"</code><code class="o">,</code> <code class="n">producer</code> <code class="o">);</code>
<code class="k">new</code> <code class="nf">Thread</code><code class="o">(</code> <code class="n">consumer</code> <code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>The <code class="literal">NamedConsumer</code> constructor
takes a string name to identify each consumer. The <a id="I_indexterm9_id717651" class="indexterm"/><code class="literal">run()</code> method uses this
name in the call to <code class="literal">println()</code> to
identify which consumer received the message.</p><p>The only required modification to the <code class="literal">Producer</code> code is to change the <code class="literal">notify()</code> calls to <code class="literal">notifyAll()</code> calls in <code class="literal">putMessage()</code> and <code class="literal">getMessage()</code>. (We could have used <code class="literal">notifyAll()</code> in the first place.) Now, instead
of the consumer and producer playing tag with the queue, we can have
many players waiting for the condition of the queue to change. We might
have a number of consumers waiting for a message, or we might have the
producer waiting for a consumer to take a message. Any time the
condition of the queue changes, we prod all of the waiting methods to
reevaluate the situation by calling <code class="literal">notifyAll()</code>.</p><p>Here is some sample output when two <code class="literal">NamedConsumers</code> are running, as in the <code class="literal">main()</code> method shown previously:</p><a id="I_9_tt510"/><pre class="programlisting"> <code class="n">One</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">01</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">Two</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">02</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">One</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">03</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">Two</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">04</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">One</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">05</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">Two</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">06</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">One</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">07</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="n">Two</code> <code class="n">got</code> <code class="nl">message:</code> <code class="n">Sat</code> <code class="n">Mar</code> <code class="mi">18</code> <code class="mi">20</code><code class="o">:</code><code class="mi">00</code><code class="o">:</code><code class="mi">08</code> <code class="n">CST</code> <code class="mi">2006</code>
<code class="o">...</code></pre><p>We see nice, orderly alternation between the two consumers as a
result of the calls to <a id="I_indexterm9_id717740" class="indexterm"/><code class="literal">sleep()</code> in the various
methods. Interesting things would happen, however, if we were to remove
all calls to <code class="literal">sleep()</code> and let things
run at full speed. The threads would compete, and their behavior would
depend on whether the system is using time-slicing. On a time-sliced