epubjs
Version:
Render ePub documents in the browser, across many devices
66 lines (65 loc) • 6.5 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Thread Performance</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="Thread Performance"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-9-SECT-6"/>Thread Performance</h1></div></div></div><p>The way that applications use threads and the associated costs and
benefits have greatly impacted the design of many Java APIs. We will
discuss some of the issues in detail in other chapters. But it is worth
briefly mentioning some aspects of thread performance and how the use of
threads has dictated the form and functionality of several recent Java
packages.</p><div class="sect2" title="The Cost of Synchronization"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-6.1"/>The Cost of Synchronization</h2></div></div></div><p><a id="idx10496" class="indexterm"/>The act of acquiring locks to synchronize threads takes
time, even when there is no contention. In older implementations of
Java, this time could be significant. With newer VMs, it is almost
negligible. However, unnecessary low-level synchronization can still
slow applications by blocking threads where legitimate concurrent access
otherwise could be allowed. Because of this, two important APIs, the
Java Collections API and the Swing GUI API, were specifically crafted to
avoid unnecessary synchronization by placing it under the developer’s
control.</p><p>The <code class="literal">java.util</code> Collections API
replaces earlier, simple Java aggregate types—namely, <code class="literal">Vector</code> and <code class="literal">Hashtable</code>—with more fully featured and,
notably, unsynchronized types (<code class="literal">List</code>
and <code class="literal">Map</code>). The Collections API instead
defers to application code to synchronize access to collections when
necessary and provides special “fail fast” functionality to help detect
concurrent access and throw an exception. It also provides
synchronization “wrappers” that can provide safe access in the old
style. Special concurrent-access-friendly implementations of the
<code class="literal">Map</code> and <code class="literal">Queue</code> collections are included as part of the
<a id="I_indexterm9_id719042" class="indexterm"/><code class="literal">java.util.concurrent</code>
package. These implementations go even further in that they are written
to allow a high degree of concurrent access without any user
synchronization. We’ll talk about these in <a class="xref" href="ch11.html" title="Chapter 11. Core Utilities">Chapter 11</a>.</p><p>The Java Swing GUI, which grew out of AWT, has taken a different
approach to providing speed and safety. Swing dictates that modification
of its components (with notable exceptions) must all be done by a single
thread: the main event queue. Swing solves performance problems as well
as nasty issues of determinism in event ordering by forcing a single super-thread to control
the GUI. The application may access the event queue thread indirectly by
pushing commands onto a queue through a simple interface.<a id="I_indexterm9_id719073" class="indexterm"/></p></div><div class="sect2" title="Thread Resource Consumption"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-9-SECT-6.2"/>Thread Resource Consumption</h2></div></div></div><p><a id="I_indexterm9_id719087" class="indexterm"/>A fundamental pattern in Java, which will be illustrated
in Chapters <a class="xref" href="ch12.html" title="Chapter 12. Input/Output Facilities">12</a> and <a class="xref" href="ch13.html" title="Chapter 13. Network Programming">13</a>, is to start many threads to handle
asynchronous external resources, such as socket connections. For maximum
efficiency, a web server might be tempted to create a thread for each
client connection it is servicing. With each client having its own
thread, I/O operations may block and restart as needed. But as efficient
as this may be in terms of throughput, it is a very inefficient use of
server resources. Threads consume memory; each thread has its own
“stack” for local variables, and switching between running threads
(context switching) adds overhead to the CPU. While threads are
relatively lightweight (in theory, it is possible to have hundreds or
thousands running on a large server), at a certain point, the resources
consumed by the threads themselves start defeating the purpose of
starting more threads. Often, this point is reached with only a few
dozen threads. Creating a thread per client is not always a scalable
option.</p><p>An alternative approach is to create “thread pools” where a fixed
number of threads pull tasks from a queue and return for more when they
are finished. This recycling of threads makes for solid scalability, but
it has historically been difficult to implement efficiently for servers
in Java because stream I/O (for things like sockets) has not fully
supported nonblocking operations. This changed with Java 1.4 and the
introduction of the NIO (new I/O) package, <a id="I_indexterm9_id719134" class="indexterm"/><code class="literal">java.nio</code>. The NIO
package introduced asynchronous I/O channels: nonblocking reads and
writes plus the ability to “select” or test the readiness of streams for
moving data. Channels can also be asynchronously closed, allowing
threads to work with them gracefully. With the NIO package, it is
possible to create servers with much more sophisticated, scalable thread
patterns.</p><p>With Java 5.0, thread pools and job “executor” services were
codified as utilities as part of the new <code class="literal">java.util.concurrent</code> package, meaning you
don’t have to write these yourself. We’ll talk about them next when we
discuss the concurrency utilities in Java.</p></div></div></body></html>