epubjs
Version:
Render ePub documents in the browser, across many devices
131 lines (128 loc) • 18.9 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Scheduling and Priority</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="Scheduling and Priority"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-9-SECT-4"/>Scheduling and Priority</h1></div></div></div><p>Java makes few guarantees about how it schedules threads. Almost all
of Java’s thread scheduling is left up to the Java implementation and, to
some degree, the application. Although it might have made sense (and would
certainly have made many developers happier) if Java’s developers had
specified a scheduling algorithm, a single algorithm isn’t necessarily
suitable for all the roles that Java can play. Instead, Java’s designers
put the burden on you to write robust code that works no matter the
scheduling algorithm, and let the implementation tune the algorithm for
the best fit.<sup>[<a id="learnjava3-CHP-9-FNOTE-3" href="#ftn.learnjava3-CHP-9-FNOTE-3" class="footnote">27</a>]</sup></p><p>The priority rules that we describe next are carefully worded in the
Java language specification to be a general guideline for thread
scheduling. You should be able to rely on this behavior overall
(statistically), but it is not a good idea to write code that relies on
very specific features of the scheduler to work properly. You should
instead use the control and synchronization tools that we have described
in this chapter to coordinate your threads.<sup>[<a id="learnjava3-CHP-9-FNOTE-4" href="#ftn.learnjava3-CHP-9-FNOTE-4" class="footnote">28</a>]</sup></p><p>Every thread has a priority value. In general, any time a thread of
a higher priority than the current thread becomes runnable (is started,
stops sleeping, or is notified), it preempts the lower-priority thread and
begins executing. By default, threads with the same priority are scheduled
round-robin, which means once a thread starts to run, it continues until
it does one of the following:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>Sleeps, by calling <code class="literal">Thread.sleep()</code> or <code class="literal">wait()</code></p></li><li class="listitem"><p>Waits for a lock, in order to run a <code class="literal">synchronized</code> method</p></li><li class="listitem"><p>Blocks on I/O, for example, in a <code class="literal">read()</code> or <code class="literal">accept()</code> call</p></li><li class="listitem"><p>Explicitly yields control, by calling <code class="literal">yield()</code></p></li><li class="listitem"><p>Terminates, by completing its target method or with a <code class="literal">stop()</code> call (deprecated)</p></li></ul></div><p>This situation looks something like <a class="xref" href="ch09s04.html#learnjava3-CHP-9-FIG-4" title="Figure 9-4. Priority preemptive, round-robin scheduling">Figure 9-4</a>.</p><div class="figure"><a id="learnjava3-CHP-9-FIG-4"/><div class="figure-contents"><div class="mediaobject"><a id="I_9_tt513"/><img src="httpatomoreillycomsourceoreillyimages1707632.png" alt="Priority preemptive, round-robin scheduling"/></div></div><p class="title">Figure 9-4. Priority preemptive, round-robin scheduling</p></div><div class="sect2" title="Thread State"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-4.1"/>Thread State</h2></div></div></div><p><a id="idx10497" class="indexterm"/>At any given time, a thread is in one of five general
states that encompass its lifecycle and activities. These states are
defined in the <a id="I_indexterm9_id718152" class="indexterm"/><code class="literal">Thread.State</code>
enumeration and queried via the <a id="I_indexterm9_id718162" class="indexterm"/><code class="literal">getState()</code> method of
the <a id="I_indexterm9_id718173" class="indexterm"/><code class="literal">Thread</code> class:</p><div class="variablelist"><dl><dt><span class="term"><code class="literal">NEW</code></span></dt><dd><p><a id="I_indexterm9_id718193" class="indexterm"/>The thread has been created but not yet
started.</p></dd><dt><span class="term"><code class="literal">RUNNABLE</code></span></dt><dd><p><a id="I_indexterm9_id718209" class="indexterm"/>The normal active state of a running thread,
including the time when a thread is blocked in an I/O operation,
like a read or write or network connection.</p></dd><dt><span class="term"><code class="literal">BLOCKED</code></span></dt><dd><p><a id="I_indexterm9_id718225" class="indexterm"/>The thread is blocked, waiting to enter a
synchronized method or code block. This includes the time when a
thread has been awakened by a <code class="literal">notify()</code> and is attempting to reacquire
its lock after a <code class="literal">wait()</code>.</p></dd><dt><span class="term"><code class="literal">WAITING,
TIMED_WAITING</code></span></dt><dd><p><a id="I_indexterm9_id718253" class="indexterm"/> <a id="I_indexterm9_id718260" class="indexterm"/>The thread is waiting for another thread via a call
to <code class="literal">wait()</code> or <code class="literal">join()</code>. In the case of <code class="literal">TIMED_WAITING</code>, the call has a
timeout.</p></dd><dt><span class="term"><code class="literal">TERMINATED</code></span></dt><dd><p><a id="I_indexterm9_id718292" class="indexterm"/>The thread has completed due to a return, an
exception, or being stopped.</p></dd></dl></div><p>We can show the state of all threads in Java (in the current
thread group) with the following snippet of code:</p><a id="I_9_tt514"/><pre class="programlisting"> <code class="n">Thread</code> <code class="o">[]</code> <code class="n">threads</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Thread</code> <code class="o">[</code> <code class="mi">64</code> <code class="o">];</code> <code class="c1">// max threads to show</code>
<code class="kt">int</code> <code class="n">num</code> <code class="o">=</code> <code class="n">Thread</code><code class="o">.</code><code class="na">enumerate</code><code class="o">(</code> <code class="n">threads</code> <code class="o">);</code>
<code class="k">for</code><code class="o">(</code> <code class="kt">int</code> <code class="n">i</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code> <code class="n">i</code> <code class="o"><</code> <code class="n">num</code><code class="o">;</code> <code class="n">i</code><code class="o">++</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">threads</code><code class="o">[</code><code class="n">i</code><code class="o">]</code> <code class="o">+</code><code class="s">":"</code><code class="o">+</code> <code class="n">threads</code><code class="o">[</code><code class="n">i</code><code class="o">].</code><code class="na">getState</code><code class="o">()</code> <code class="o">);</code></pre><p>You will probably not use this API in general programming, but it
is interesting and useful for experimenting and learning about Java
threads.<a id="I_indexterm9_id718316" class="indexterm"/></p></div><div class="sect2" title="Time-Slicing"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-4.2"/>Time-Slicing</h2></div></div></div><p><a id="idx10498" class="indexterm"/>In addition to prioritization, all modern systems (with
the exception of some embedded and “micro” Java environments) implement
thread time-slicing. In a time-sliced system, thread processing is
chopped up so that each thread runs for a short period of time before
the context is switched to the next thread, as shown in <a class="xref" href="ch09s04.html#learnjava3-CHP-9-FIG-5" title="Figure 9-5. Priority preemptive, time-sliced scheduling">Figure 9-5</a>.</p><div class="figure-float"><div class="figure"><a id="learnjava3-CHP-9-FIG-5"/><div class="figure-contents"><div class="mediaobject"><a id="I_9_tt515"/><img src="httpatomoreillycomsourceoreillyimages1707633.png" alt="Priority preemptive, time-sliced scheduling"/></div></div><p class="title">Figure 9-5. Priority preemptive, time-sliced scheduling</p></div></div><p>Higher-priority threads still preempt lower-priority threads in
this scheme. The addition of time-slicing mixes up the processing among
threads of the same priority; on a multiprocessor machine, threads may
even be run simultaneously. This can introduce a difference in behavior
for applications that don’t use threads and synchronization
properly.</p><p>Strictly speaking, because Java doesn’t guarantee time-slicing,
you shouldn’t write code that relies on this type of scheduling; any
software you write should function under round-robin scheduling. If
you’re wondering what your particular flavor of Java does, try the
following experiment:</p><a id="I_9_tt516"/><pre class="programlisting"> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">Thready</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="o">{</code>
<code class="k">new</code> <code class="nf">ShowThread</code><code class="o">(</code><code class="s">"Foo"</code><code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="k">new</code> <code class="nf">ShowThread</code><code class="o">(</code><code class="s">"Bar"</code><code class="o">).</code><code class="na">start</code><code class="o">();</code>
<code class="o">}</code>
<code class="kd">static</code> <code class="kd">class</code> <code class="nc">ShowThread</code> <code class="kd">extends</code> <code class="n">Thread</code> <code class="o">{</code>
<code class="n">String</code> <code class="n">message</code><code class="o">;</code>
<code class="n">ShowThread</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="k">this</code><code class="o">.</code><code class="na">message</code> <code class="o">=</code> <code class="n">message</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="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">message</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>The <code class="literal">Thready</code> class starts up two
<code class="literal">ShowThread</code> objects. <code class="literal">ShowThread</code> is a thread that goes into a hard
loop (very bad form) and prints its message. Because we don’t specify a
priority for either thread, they both inherit the priority of their
creator, so they have the same priority. When you run this example, you
will see how your Java implementation does its scheduling. Under a
round-robin scheme, only “Foo” should be printed; “Bar” never appears.
In a time-slicing implementation, you should occasionally see the “Foo”
and “Bar” messages alternate (which is most likely what you will
see).<a id="I_indexterm9_id718428" class="indexterm"/></p></div><div class="sect2" title="Priorities"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-4.3"/>Priorities</h2></div></div></div><p><a id="I_indexterm9_id718442" class="indexterm"/>As we said before, the priorities of threads exist as a
general guideline for how the implementation should allocate time among
competing threads. Unfortunately, with the complexity of how Java
threads are mapped to native thread implementations, you cannot rely
upon the exact meaning of priorities. Instead, you should only consider
them a hint to the VM.</p><p>Let’s play with the priority of our threads:</p><a id="I_9_tt517"/><pre class="programlisting"> <code class="kd">class</code> <code class="nc">Thready</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="o">{</code>
<code class="n">Thread</code> <code class="n">foo</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ShowThread</code><code class="o">(</code><code class="s">"Foo"</code><code class="o">);</code>
<code class="n">foo</code><code class="o">.</code><code class="na">setPriority</code><code class="o">(</code> <code class="n">Thread</code><code class="o">.</code><code class="na">MIN_PRIORITY</code> <code class="o">);</code>
<code class="n">Thread</code> <code class="n">bar</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ShowThread</code><code class="o">(</code><code class="s">"Bar"</code><code class="o">);</code>
<code class="n">bar</code><code class="o">.</code><code class="na">setPriority</code><code class="o">(</code> <code class="n">Thread</code><code class="o">.</code><code class="na">MAX_PRIORITY</code> <code class="o">);</code>
<code class="n">bar</code><code class="o">.</code><code class="na">start</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>We would expect that with this change to our <code class="literal">Thready</code> class, the Bar thread would take over
completely. If you run this code on the Solaris implementation of Java
5.0, that’s what happens. The same is not true on Windows or with some
older versions of Java. Similarly, if you change the priorities to
values other than min and max, you may not see any difference at all.
The subtleties relating to priority and performance relate to how Java
threads and priorities are mapped to real threads in the OS. For this
reason, thread priorities should be reserved for system and framework
development.</p></div><div class="sect2" title="Yielding"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-4.5"/>Yielding</h2></div></div></div><p><a id="idx10499" class="indexterm"/>Whenever a thread sleeps, waits, or blocks on I/O, it
gives up its time slot and another thread is scheduled. As long as you
don’t write methods that use hard loops, all threads should get their
due. However, a thread can also signal that it is willing to give up its
time voluntarily at any point with the <a id="I_indexterm9_id718513" class="indexterm"/><code class="literal">yield()</code> call. We can
change our previous example to include a <code class="literal">yield()</code> on each iteration:</p><a id="I_9_tt518"/><pre class="programlisting"> <code class="o">...</code>
<code class="kd">static</code> <code class="kd">class</code> <code class="nc">ShowThread</code> <code class="kd">extends</code> <code class="n">Thread</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">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">message</code> <code class="o">);</code>
<code class="n">yield</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>You should see “Foo” and “Bar” messages strictly alternating. If
you have threads that perform very intensive calculations or otherwise
eat a lot of CPU time, you might want to find an appropriate place for
them to yield control occasionally. Alternatively, you might want to
drop the priority of your compute-intensive thread so that more
important processing can proceed around it.</p><p>Unfortunately, the Java language specification is very weak with
respect to <code class="literal">yield()</code>. It is another one
of those things that you should consider an optimization hint rather
than a guarantee. In the worst case, the runtime system may simply
ignore calls to <code class="literal">yield()</code>.<a id="I_indexterm9_id718562" class="indexterm"/></p></div><div class="footnotes"><br/><hr/><div class="footnote"><p><sup>[<a id="ftn.learnjava3-CHP-9-FNOTE-3" href="#learnjava3-CHP-9-FNOTE-3" class="para">27</a>] </sup>A notable alternative to this is the real-time Java
specification that defines specialized thread behavior for certain
types of applications. It was developed under the Java community
process and can be found at <a class="ulink" href="https://rtsj.dev.java.net/">https://rtsj.dev.java.net/</a>.</p></div><div class="footnote"><p><sup>[<a id="ftn.learnjava3-CHP-9-FNOTE-4" href="#learnjava3-CHP-9-FNOTE-4" class="para">28</a>] </sup><a id="I_indexterm9_id718022" class="indexterm"/><a id="I_indexterm9_id718027" class="indexterm"/><a id="I_indexterm9_id718032" class="indexterm"/><span class="emphasis"><em>Java Threads</em></span> by Scott Oaks and
Henry Wong (O’Reilly) includes a detailed discussion of
synchronization, scheduling, and other thread-related issues.</p></div></div></div></body></html>