📄 tij315.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html lang="en">
<!--
This document was converted from RTF source:
By r2net 5.8 r2netcmd Windows
See http://www.logictran.com
-->
<head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Thinking in Java, 3rd ed. Revision 4.0: 13: Concurrency</title>
<link rel="stylesheet" href="stylesheet.css" type="text/css"></head>
<body >
<CENTER> <a href="http://www.MindView.net"> <img src="mindview.gif" alt="MindView Inc." BORDER = "0"></a> <Font FACE="Verdana, Tahoma, Arial, Helvetica, Sans"> <h2>Thinking in Java, 3<sup>rd</sup> ed. Revision 4.0</h2> <FONT size = "-1"><br> [ <a href="README.txt">Viewing Hints</a> ] [ <a href="http://www.mindview.net/Books/TIJ/">Book Home Page</a> ] [ <a href="http://www.mindview.net/Etc/MailingList.html">Free Newsletter</a> ] <br> [ <a href="http://www.mindview.net/Seminars">Seminars</a> ] [ <a href="http://www.mindview.net/CDs">Seminars on CD ROM</a> ] [ <a href="http://www.mindview.net/Services">Consulting</a> ] <br><br> </FONT></FONT> </CENTER>
<font face="Georgia"><div align="CENTER"><a href="TIJ314.htm" target="RightFrame"><img src="./prev.gif" alt="Previous " border="0"></a>
<a href="TIJ316.htm" target="RightFrame"><img src="./next.gif" alt="Next " border="0"></a>
<a href="TIJ3_t.htm"><img src="./first.gif" alt="Title Page " border="0"></a>
<a href="TIJ3_i.htm"><img src="./index.gif" alt="Index " border="0"></a>
<a href="TIJ3_c.htm"><img src="./contents.gif" alt="Contents " border="0"></a>
</div>
<hr>
<h1>
<a name="_Toc375545444"></a><a name="_Toc375545471"></a><a name="_Toc24272652"></a><a name="_Toc24775835"></a><a name="Heading16832"></a>13:
Concurrency</h1>
<p class="Intro">Objects provide a way to divide a program into independent sections. Often, you also need to turn a program into separate, independently running subtasks.<br></p>
<p>Each of these independent subtasks is called a <a name="Index1527"></a><a name="Index1528"></a><i>thread</i>, and you program as if each thread runs by itself and has the CPU to itself. Some underlying mechanism is actually dividing up the CPU time for you, but in general, you don’t have to think about it, which makes programming with multiple threads a much easier task. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2194" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>A <a name="Index1529"></a><i>process</i> is a self-contained running program with its own address space. A <a name="Index1530"></a><i>multitasking</i> operating system is capable of running more than one process (program) at a time, while making it look like each one is chugging along on its own, by periodically switching the CPU from one task to another. A thread is a single sequential flow of control within a process. A single process can thus have multiple concurrently executing threads. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2195" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>There are many possible uses for multithreading, but in general, you’ll have some part of your program tied to a particular event or resource, and you don’t want that to hold up the rest of your program. So, you create a thread associated with that event or resource and let it run independently of the main program. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2196" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Concurrent programming is like stepping into an entirely new world and learning a new programming language, or at least a new set of language concepts. With the appearance of thread support in most microcomputer operating systems, extensions for threads have also been appearing in programming languages or libraries. In all cases, thread programming:<br></p>
<ol>
<li>Seems mysterious and requires a shift in the way you think about
programming</li>
<li>Looks similar to thread support in other languages, so when you understand
threads, you understand a common tongue
</li></ol><p>And although support for threads can make Java a more complicated language, this isn’t entirely the fault of Java—threads are tricky. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2348" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Understanding concurrent programming is on the same order of difficulty as understanding polymorphism. If you apply some effort, you can fathom the basic mechanism, but it generally takes deep study and understanding in order to develop a true grasp of the subject. The goal of this chapter is to give you a solid foundation in the basics of concurrency so that you can understand the concepts and write reasonable multithreaded programs. Be aware that you can easily become overconfident, so if you are writing anything complex, you will need to study dedicated books on the topic. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0170" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc24775836"></a><a name="Heading16842"></a>Motivation</h2>
<p>One of the most compelling reasons for concurrency is to produce a responsive user interface. Consider a program that performs some CPU-intensive operation and thus ends up ignoring user input and being unresponsive. The basic problem is that the program needs to continue performing its operations, and at the same time it needs to return control to the user interface so that the program can respond to the user. If you have a “quit” button, you don’t want to be forced to poll it in every piece of code you write in your program, and yet you want the quit button to be responsive, as if you <a name="Index1531"></a><i>were</i> checking it regularly. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0169" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>A conventional method cannot continue performing its operations and at the same time return control to the rest of the program. In fact, this sounds like an impossible thing to accomplish, as if the CPU must be in two places at once, but this is precisely the illusion that concurrency provides. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2201" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Concurrency can also be used to optimize throughput. For example, you might be able to do important work while you’re stuck waiting for input to arrive on an I/O port. Without threading, the only reasonable solution is to poll the I/O port, which is awkward and can be difficult. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0361" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>If you have a multiprocessor machine, multiple threads may be distributed across multiple processors, which can dramatically improve throughput. This is often the case with powerful multiprocessor web servers, which can distribute large numbers of user requests across CPUs in a program that allocates one thread per request. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0171" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>One thing to keep in mind is that a program with many threads must be able to run on a single-CPU machine. Therefore, it must also be possible to write the same program without using any threads. However, multithreading provides a very important organizational benefit, so that the design of your program can be greatly simplified. Some types of problems, such as simulation—a video game, for example—are very difficult to solve without support for concurrency. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0362" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The threading model is a programming convenience to simplify juggling several operations at the same time within a single program. With threads, the CPU will pop around and give each thread some of its time. Each thread has the consciousness of constantly having the CPU to itself, but the CPU’s time is actually sliced between all the threads. The exception to this is if your program is running on multiple CPUs, but one of the great things about threading is that you are abstracted away from this layer, so your code does not need to know whether it is actually running on a single CPU or many. Thus, threads are a way to create transparently scalable programs—if a program is running too slowly, it can easily be made faster by adding CPUs to your computer. Multitasking and multithreading tend to be the most reasonable ways to utilize multiprocessor systems. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2202" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p><a name="Index1532"></a><a name="Index1533"></a>Threading can reduce computing efficiency somewhat in single-CPU machines, but the net improvement in program design, resource balancing, and user convenience is often quite valuable. In general, threads enable you to create a more loosely-coupled design; otherwise, parts of your code would be forced to pay explicit attention to tasks that would normally be handled by threads. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2203" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc24775837"></a><a name="Heading16850"></a>Basic threads</h2>
<p>The simplest way to create a thread is to inherit from <b>java.lang.Thread</b>, which has all the wiring necessary to create and run threads. The most important method for <b>Thread</b> is <b>run( )</b>, which you must override to make the thread do your bidding. Thus, <b>run( )</b> is the code that will be executed “simultaneously” with the other threads in a program. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2204" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The following example creates five threads, each with a unique identification number generated with a <b>static</b> variable. The <a name="Index1534"></a><b>Thread</b>’s <b>run( )</b> method is overridden to count down each time it passes through its loop and to return when the count is zero (at the point when <b>run( )</b> returns, the thread is terminated by the threading mechanism). <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0177" title="Send BackTalk Comment">Feedback</a></font><br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c13:SimpleThread.java</font>
<font color=#009900>// Very simple Threading example.</font>
<font color=#0000ff>import</font> com.bruceeckel.simpletest.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> SimpleThread <font color=#0000ff>extends</font> Thread {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> Test monitor = <font color=#0000ff>new</font> Test();
<font color=#0000ff>private</font> <font color=#0000ff>int</font> countDown = 5;
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>int</font> threadCount = 0;
<font color=#0000ff>public</font> SimpleThread() {
<font color=#0000ff>super</font>(<font color=#004488>""</font> + ++threadCount); <font color=#009900>// Store the thread name</font>
start();
}
<font color=#0000ff>public</font> String toString() {
<font color=#0000ff>return</font> <font color=#004488>"#"</font> + getName() + <font color=#004488>": "</font> + countDown;
}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> run() {
<font color=#0000ff>while</font>(<font color=#0000ff>true</font>) {
System.out.println(<font color=#0000ff>this</font>);
<font color=#0000ff>if</font>(--countDown == 0) <font color=#0000ff>return</font>;
}
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < 5; i++)
<font color=#0000ff>new</font> SimpleThread();
monitor.expect(<font color=#0000ff>new</font> String[] {
<font color=#004488>"#1: 5"</font>,
<font color=#004488>"#2: 5"</font>,
<font color=#004488>"#3: 5"</font>,
<font color=#004488>"#5: 5"</font>,
<font color=#004488>"#1: 4"</font>,
<font color=#004488>"#4: 5"</font>,
<font color=#004488>"#2: 4"</font>,
<font color=#004488>"#3: 4"</font>,
<font color=#004488>"#5: 4"</font>,
<font color=#004488>"#1: 3"</font>,
<font color=#004488>"#4: 4"</font>,
<font color=#004488>"#2: 3"</font>,
<font color=#004488>"#3: 3"</font>,
<font color=#004488>"#5: 3"</font>,
<font color=#004488>"#1: 2"</font>,
<font color=#004488>"#4: 3"</font>,
<font color=#004488>"#2: 2"</font>,
<font color=#004488>"#3: 2"</font>,
<font color=#004488>"#5: 2"</font>,
<font color=#004488>"#1: 1"</font>,
<font color=#004488>"#4: 2"</font>,
<font color=#004488>"#2: 1"</font>,
<font color=#004488>"#3: 1"</font>,
<font color=#004488>"#5: 1"</font>,
<font color=#004488>"#4: 1"</font>
}, Test.IGNORE_ORDER + Test.WAIT);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p>The thread objects are given specific names by calling the appropriate <b>Thread</b> constructor. This name is retrieved in <b>toString( ) </b>using <b>getName( )</b>.<br></p>
<p>A <b>Thread </b>object’s <b>run( )</b> method virtually always has some kind of loop that continues until the thread is no longer necessary, so you must establish the condition on which to break out of this loop (or, as in the preceding program, simply <b>return</b> from <b>run( )</b>). Often, <b>run( )</b> is cast in the form of an infinite loop, which means that, barring some factor that causes <b>run( )</b> to terminate, it will continue forever (later in the chapter you’ll see how to safely signal a thread to stop). <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2205" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>In <b>main( ) </b>you can see a number of threads being created and run. The <b>start( ) </b>method in the <a name="Index1535"></a><b>Thread</b> class performs special initialization for the thread and then calls <b>run( )</b>. So the steps are: the constructor is called to build the object, it calls <b>start( )</b> to configure the thread, and the thread execution mechanism calls <b>run( )</b>. If you don’t call <b>start( )</b> (which you don’t have to do in the constructor, as you will see in subsequent examples), the thread will never be started. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2206" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The output for one run of this program will be different from that of another, because the thread scheduling mechanism is not deterministic. In fact, you may see dramatic differences in the output of this simple program between one version of the JDK and the next. For example, a previous JDK didn’t time-slice very often, so thread 1 might loop to extinction first, then thread 2 would go through all of its loops, etc. This was virtually the same as calling a routine that would do all the loops at once, except that starting up all those threads is more expensive. In JDK 1.4 you get something like the output from <b>SimpleThread.java</b>, which indicates better time-slicing behavior by the scheduler—each thread seems to be getting regular service. Generally, these kinds of JDK behavioral changes have not been mentioned by Sun, so you cannot plan on any consistent threading behavior. The best approach is to be as conservative as possible while writing threading code. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0172" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>When <b>main( )</b> creates the <b>Thread</b> objects, it isn’t capturing the references for any of them. With an ordinary object, this would make it fair game for garbage collection, but not with a <b>Thread</b>. Each <b>Thread</b> “registers” itself so there is actually a reference to it someplace, and the garbage collector can’t clean it up until the thread exits its <b>run( )</b> and dies. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap14_2209" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc24775838"></a><a name="Heading16912"></a>Yielding</h3>
<p>If you know that you’ve accomplished what you need to in your <b>run( )</b> method, you can give a hint to the thread scheduling mechanism that you’ve done enough and that some other thread might as well have the CPU. This hint (and it <i>is</i> a hint—there’s no guarantee your implementation will listen to it) takes the form of the <a name="Index1536"></a><b>yield( )</b> method. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0176" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>We can modify the preceding example by yielding after each loop:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c13:YieldingThread.java</font>
<font color=#009900>// Suggesting when to switch threads with yield().</font>
<font color=#0000ff>import</font> com.bruceeckel.simpletest.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> YieldingThread <font color=#0000ff>extends</font> Thread {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> Test monitor = <font color=#0000ff>new</font> Test();
<font color=#0000ff>private</font> <font color=#0000ff>int</font> countDown = 5;
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>int</font> threadCount = 0;
<font color=#0000ff>public</font> YieldingThread() {
<font color=#0000ff>super</font>(<font color=#004488>""</font> + ++threadCount);
start();
}
<font color=#0000ff>public</font> String toString() {
<font color=#0000ff>return</font> <font color=#004488>"#"</font> + getName() + <font color=#004488>": "</font> + countDown;
}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> run() {
<font color=#0000ff>while</font>(<font color=#0000ff>true</font>) {
System.out.println(<font color=#0000ff>this</font>);
<font color=#0000ff>if</font>(--countDown == 0) <font color=#0000ff>return</font>;
yield();
}
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < 5; i++)
<font color=#0000ff>new</font> YieldingThread();
monitor.expect(<font color=#0000ff>new</font> String[] {
<font color=#004488>"#1: 5"</font>,
<font color=#004488>"#2: 5"</font>,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -