﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-AntiquMan-随笔分类-Thread</title><link>http://www.blogjava.net/AntiquMan/category/38695.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 05 Aug 2009 15:19:10 GMT</lastBuildDate><pubDate>Wed, 05 Aug 2009 15:19:10 GMT</pubDate><ttl>60</ttl><item><title>(转)队列和线程池简单示例 </title><link>http://www.blogjava.net/AntiquMan/archive/2009/08/03/289644.html</link><dc:creator>AntiquMan</dc:creator><author>AntiquMan</author><pubDate>Mon, 03 Aug 2009 10:18:00 GMT</pubDate><guid>http://www.blogjava.net/AntiquMan/archive/2009/08/03/289644.html</guid><wfw:comment>http://www.blogjava.net/AntiquMan/comments/289644.html</wfw:comment><comments>http://www.blogjava.net/AntiquMan/archive/2009/08/03/289644.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AntiquMan/comments/commentRss/289644.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AntiquMan/services/trackbacks/289644.html</trackback:ping><description><![CDATA[<span  style="font-family: verdana, sans-serif; font-size: 14px; line-height: 21px; ">
<p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 1em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; "><span class="Apple-tab-span" style="white-space:pre">	</span>基本演示了线程池和队列的应用</p>
<p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 1em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; ">&nbsp;&nbsp;<span style="line-height: 21px; color: #333333; ">public&nbsp;class&nbsp;WorkQueue {&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span></p>
<p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 1em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; "><span style="line-height: 21px; color: #333333; ">&nbsp;&nbsp; private&nbsp;final&nbsp;int&nbsp;nThreads;//线程池的大小&nbsp;<br />
&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;PoolWorker[]&nbsp;threads;//用数组实现线程池&nbsp;<br />
&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;LinkedList&nbsp;queue;//任务队列&nbsp;<br />
<br />
&nbsp;&nbsp;public&nbsp;WorkQueue(int&nbsp;nThreads){&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.nThreads&nbsp;=&nbsp;nThreads;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue&nbsp;=&nbsp;new&nbsp;LinkedList();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads&nbsp;=&nbsp;new&nbsp;PoolWorker[nThreads];&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i=0;&nbsp;i&lt;nThreads;i++){</span></p>
<p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 1em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; "><span style="line-height: 21px; color: #333333; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;threads[i]&nbsp;=&nbsp;new&nbsp;PoolWorker();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i].start();//启动所有工作线程&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;}&nbsp;<br />
<br />
&nbsp;&nbsp;public&nbsp;void&nbsp;execute(Runnable&nbsp;r)&nbsp;{//</span><span style="line-height: 21px; color: #333333; ">任务&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;synchronized(queue)&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.addLast(r);&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.notify();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;}&nbsp;<br />
<br />
&nbsp;&nbsp;private&nbsp;class&nbsp;PoolWorker&nbsp;extends&nbsp;Thread&nbsp;{//工作线程类&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Runnable&nbsp;r;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(true)&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;synchronized(queue)&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(queue.isEmpty())&nbsp;{//如果任务队列中没有任务，等待&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.wait();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch&nbsp;(InterruptedException&nbsp;ignored){}&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;(Runnable)&nbsp;queue.removeFirst();//有任务时，取出任务&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.run();//执行任务&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch&nbsp;(RuntimeException&nbsp;e)&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;You&nbsp;might&nbsp;want&nbsp;to&nbsp;log&nbsp;something&nbsp;here&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;&nbsp;}&nbsp;<br />
<br />
<br />
&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[]){&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkQueue&nbsp;wq=new&nbsp;WorkQueue(10);//10个工作线程&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Mytask&nbsp;r[]=new&nbsp;Mytask[20];//20个任务&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;i&lt;20;i++){&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r[i]=new&nbsp;Mytask();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wq.execute(r[i]);&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;}&nbsp;<br />
}&nbsp;<br />
class&nbsp;Mytask&nbsp;implements&nbsp;Runnable{//任务接口&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run(){&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;name=Thread.currentThread().getName();&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(100);//模拟任务执行的时间&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch(InterruptedException&nbsp;e){}&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(name+"&nbsp;executed&nbsp;OK");&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;}&nbsp;</span></p>
</span>
<img src ="http://www.blogjava.net/AntiquMan/aggbug/289644.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AntiquMan/" target="_blank">AntiquMan</a> 2009-08-03 18:18 <a href="http://www.blogjava.net/AntiquMan/archive/2009/08/03/289644.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java线程：线程的同步 </title><link>http://www.blogjava.net/AntiquMan/archive/2009/07/03/285349.html</link><dc:creator>AntiquMan</dc:creator><author>AntiquMan</author><pubDate>Fri, 03 Jul 2009 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/AntiquMan/archive/2009/07/03/285349.html</guid><wfw:comment>http://www.blogjava.net/AntiquMan/comments/285349.html</wfw:comment><comments>http://www.blogjava.net/AntiquMan/archive/2009/07/03/285349.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AntiquMan/comments/commentRss/285349.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AntiquMan/services/trackbacks/285349.html</trackback:ping><description><![CDATA[<div align="left"><strong>一、同步问题提出</strong></div>
<div align="left">&nbsp;</div>
<div align="left">线程的同步是为了防止多个线程访问一个数据对象时，对数据造成的破坏。</div>
<div align="left">例如：两个线程ThreadA、ThreadB都操作同一个对象Foo对象，并修改Foo对象上的数据。</div>
<div align="left">&nbsp;</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee"><font color="#0000ff">public</font> <font color="#0000ff">class</font> Foo { <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> <font color="#0000ff">int</font> x = 100; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">int</font> getX() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> x; <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">int</font> fix(<font color="#0000ff">int</font> y) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x = x - y; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> x; <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
}</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee"><font color="#0000ff">public</font> <font color="#0000ff">class</font> MyRunnable <font color="#0000ff">implements</font> Runnable { <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> Foo foo = <font color="#0000ff">new</font> Foo(); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyRunnable r = <font color="#0000ff">new</font> MyRunnable(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread ta = <font color="#0000ff">new</font> Thread(r, <font color="#800000">"Thread-A"</font>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread tb = <font color="#0000ff">new</font> Thread(r, <font color="#800000">"Thread-B"</font>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ta.start(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tb.start(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">void</font> run() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">for</font> (<font color="#0000ff">int</font> i = 0; i &lt; 3; i++) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">this</font>.fix(30); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">try</font> { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <font color="#0000ff">catch</font> (InterruptedException e) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Thread.currentThread().getName() + <font color="#800000">" : 当前foo对象的x值= "</font> + foo.getX()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">int</font> fix(<font color="#0000ff">int</font> y) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> foo.fix(y); <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
}</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">运行结果：</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee">Thread-A : 当前foo对象的x值= 40 <br />
Thread-B : 当前foo对象的x值= 40 <br />
Thread-B : 当前foo对象的x值= -20 <br />
Thread-A : 当前foo对象的x值= -50 <br />
Thread-A : 当前foo对象的x值= -80 <br />
Thread-B : 当前foo对象的x值= -80 <br />
<br />
Process finished with exit code 0</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">从结果发现，这样的输出值明显是不合理的。原因是两个线程不加控制的访问Foo对象并修改其数据所致。</div>
<div align="left">&nbsp;</div>
<div align="left">如果要保持结果的合理性，只需要达到一个目的，就是将对Foo的访问加以限制，每次只能有一个线程在访问。这样就能保证Foo对象中数据的合理性了。</div>
<div align="left">&nbsp;</div>
<div align="left">在具体的Java代码中需要完成一下两个操作：</div>
<div align="left">把竞争访问的资源类Foo变量x标识为private；</div>
<div align="left">同步哪些修改变量的代码，使用synchronized关键字同步方法或代码。</div>
<div align="left">&nbsp;</div>
<div align="left"><strong>二、同步和锁定</strong></div>
<div align="left">&nbsp;</div>
<div align="left">1、锁的原理</div>
<div align="left">&nbsp;</div>
<div align="left">Java中每个对象都有一个内置锁</div>
<div align="left">&nbsp;</div>
<div align="left">当程序运行到非静态的synchronized同步方法上时，自动获得与正在执行代码类的当前实例（this实例）有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。</div>
<div align="left">&nbsp;</div>
<div align="left">当程序运行到synchronized同步方法或代码块时才该对象锁才起作用。</div>
<div align="left">&nbsp;</div>
<div align="left">一个对象只有一个锁。所以，如果一个线程获得该锁，就没有其他线程可以获得锁，直到第一个线程释放（或返回）锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块，直到该锁被释放。</div>
<div align="left">&nbsp;</div>
<div align="left">释放锁是指持锁线程退出了synchronized同步方法或代码块。</div>
<div align="left">&nbsp;</div>
<div align="left">关于锁和同步，有一下几个要点：</div>
<div align="left">1）、只能同步方法，而不能同步变量和类；</div>
<div align="left">2）、每个对象只有一个锁；当提到同步时，应该清楚在什么上同步？也就是说，在哪个对象上同步？</div>
<div align="left">3）、不必同步类中所有的方法，类可以同时拥有同步和非同步方法。</div>
<div align="left">4）、如果两个线程要执行一个类中的synchronized方法，并且两个线程使用相同的实例来调用方法，那么一次只能有一个线程能够执行方法，另一个需要等待，直到锁被释放。也就是说：如果一个线程在对象上获得一个锁，就没有任何其他线程可以进入（该对象的）类中的任何一个同步方法。</div>
<div align="left">5）、如果线程拥有同步和非同步方法，则非同步方法可以被多个线程自由访问而不受锁的限制。</div>
<p align="left">6）、线程睡眠时，它所持的任何锁都不会释放。 </p>
<div align="left">7）、线程可以获得多个锁。比如，在一个对象的同步方法里面调用另外一个对象的同步方法，则获取了两个对象的同步锁。</div>
<div align="left">8）、同步损害并发性，应该尽可能缩小同步范围。同步不但可以同步整个方法，还可以同步方法中一部分代码块。</div>
<div align="left">9）、在使用同步代码块时候，应该指定在哪个对象上同步，也就是说要获取哪个对象的锁。例如：</div>
<div align="left">&nbsp;&nbsp;&nbsp; public int fix(int y) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized (this) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = x - y;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return x;<br />
&nbsp;&nbsp;&nbsp; }</div>
<div align="left">&nbsp;</div>
<div align="left">当然，同步方法也可以改写为非同步方法，但功能完全一样的，例如：</div>
<div align="left">&nbsp;&nbsp;&nbsp; public synchronized int getX() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return x++;<br />
&nbsp;&nbsp;&nbsp; }</div>
<div align="left">与</div>
<div align="left">&nbsp;&nbsp;&nbsp; public int getX() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized (this) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return x;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</div>
<div align="left">效果是完全一样的。</div>
<div align="left">&nbsp;</div>
<div align="left"><strong>三、静态方法同步</strong></div>
<div align="left">&nbsp;</div>
<div align="left">要同步静态方法，需要一个用于整个类对象的锁，这个对象是就是这个类（XXX.class)。</div>
<div align="left">例如：</div>
<div align="left">public static synchronized int setName(String name){</div>
<div align="left">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Xxx.name = name;</div>
<div align="left">}</div>
<div align="left">等价于<br />
public static int setName(String name){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(Xxx.class){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Xxx.name = name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}</div>
<div align="left"><br />
&nbsp;</div>
<div align="left"><strong>四、如果线程不能不能获得锁会怎么样</strong></div>
<div align="left">&nbsp;</div>
<div align="left">如果线程试图进入同步方法，而其锁已经被占用，则线程在该对象上被阻塞。实质上，线程进入该对象的的一种池中，必须在哪里等待，直到其锁被释放，该线程再次变为可运行或运行为止。</div>
<div align="left">&nbsp;</div>
<div align="left">当考虑阻塞时，一定要注意哪个对象正被用于锁定：</div>
<div align="left">1、调用同一个对象中非静态同步方法的线程将彼此阻塞。如果是不同对象，则每个线程有自己的对象的锁，线程间彼此互不干预。</div>
<div align="left">&nbsp;</div>
<div align="left">2、调用同一个类中的静态同步方法的线程将彼此阻塞，它们都是锁定在相同的Class对象上。</div>
<div align="left">&nbsp;</div>
<div align="left">3、静态同步方法和非静态同步方法将永远不会彼此阻塞，因为静态方法锁定在Class对象上，非静态方法锁定在该类的对象上。</div>
<div align="left">&nbsp;</div>
<div align="left">4、对于同步代码块，要看清楚什么对象已经用于锁定（synchronized后面括号的内容）。在同一个对象上进行同步的线程将彼此阻塞，在不同对象上锁定的线程将永远不会彼此阻塞。</div>
<div align="left">&nbsp;</div>
<div align="left"><strong>五、何时需要同步</strong></div>
<div align="left">&nbsp;</div>
<div align="left">在多个线程同时访问互斥（可交换）数据时，应该同步以保护数据，确保两个线程不会同时修改更改它。</div>
<div align="left">&nbsp;</div>
<div align="left">对于非静态字段中可更改的数据，通常使用非静态方法访问。</div>
<div align="left">对于静态字段中可更改的数据，通常使用静态方法访问。</div>
<div align="left">&nbsp;</div>
<div align="left">如果需要在非静态方法中使用静态字段，或者在静态字段中调用非静态方法，问题将变得非常复杂。已经超出SJCP考试范围了。</div>
<div align="left">&nbsp;</div>
<div align="left"><strong>六、线程安全类</strong></div>
<div align="left">&nbsp;</div>
<div align="left">当一个类已经很好的同步以保护它的数据时，这个类就称为&#8220;线程安全的&#8221;。</div>
<div align="left">&nbsp;</div>
<div align="left">即使是线程安全类，也应该特别小心，因为操作的线程是间仍然不一定安全。</div>
<div align="left">&nbsp;</div>
<div align="left">举个形象的例子，比如一个集合是线程安全的，有两个线程在操作同一个集合对象，当第一个线程查询集合非空后，删除集合中所有元素的时候。第二个线程也来执行与第一个线程相同的操作，也许在第一个线程查询后，第二个线程也查询出集合非空，但是当第一个执行清除后，第二个再执行删除显然是不对的，因为此时集合已经为空了。</div>
<div align="left">看个代码：</div>
<div align="left">&nbsp;</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee"><font color="#0000ff">public</font> <font color="#0000ff">class</font> NameList { <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> List nameList = Collections.synchronizedList(<font color="#0000ff">new</font> LinkedList()); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">void</font> add(String name) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nameList.add(name); <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> String removeFirst() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> (nameList.size() &gt; 0) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> (String) nameList.remove(0); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <font color="#0000ff">else</font> { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> <font color="#0000ff">null</font>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
}</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee"><font color="#0000ff">public</font> <font color="#0000ff">class</font> Test { <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">final</font> NameList nl = <font color="#0000ff">new</font> NameList(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nl.add(<font color="#800000">"aaa"</font>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">class</font> NameDropper <font color="#0000ff">extends</font> Thread{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">void</font> run(){ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String name = nl.removeFirst(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(name); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread t1 = <font color="#0000ff">new</font> NameDropper(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread t2 = <font color="#0000ff">new</font> NameDropper(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1.start(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2.start(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
}</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">虽然集合对象</div>
<div align="left">&nbsp;&nbsp;&nbsp; private List nameList = Collections.synchronizedList(new LinkedList());<br />
是同步的，但是程序还不是线程安全的。</div>
<div align="left">出现这种事件的原因是，上例中一个线程操作列表过程中无法阻止另外一个线程对列表的其他操作。</div>
<div align="left">&nbsp;</div>
<div align="left">解决上面问题的办法是，在操作集合对象的NameList上面做一个同步。改写后的代码如下：</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee"><font color="#0000ff">public</font> <font color="#0000ff">class</font> NameList { <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> List nameList = Collections.synchronizedList(<font color="#0000ff">new</font> LinkedList()); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">synchronized</font> <font color="#0000ff">void</font> add(String name) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nameList.add(name); <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">synchronized</font> String removeFirst() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> (nameList.size() &gt; 0) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> (String) nameList.remove(0); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <font color="#0000ff">else</font> { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> <font color="#0000ff">null</font>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
}</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">这样，当一个线程访问其中一个同步方法时，其他线程只有等待。</div>
<div align="left">&nbsp;</div>
<div align="left"><strong>七、线程死锁</strong></div>
<div align="left">&nbsp;</div>
<div align="left">死锁对Java程序来说，是很复杂的，也很难发现问题。当两个线程被阻塞，每个线程在等待另一个线程时就发生死锁。</div>
<div align="left">&nbsp;</div>
<div align="left">还是看一个比较直观的死锁例子：</div>
<div align="left">&nbsp;</div>
<div align="left">
<div style="border-right: #cccccc 1px solid; padding-right: 4px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 10pt; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; color: #000000; word-break: break-all; line-height: 16px; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: verdana,宋体; background-color: #eeeeee"><font color="#0000ff">public</font> <font color="#0000ff">class</font> DeadlockRisk { <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> <font color="#0000ff">static</font> <font color="#0000ff">class</font> Resource { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">int</font> value; <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> Resource resourceA = <font color="#0000ff">new</font> Resource(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">private</font> Resource resourceB = <font color="#0000ff">new</font> Resource(); <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">int</font> read() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">synchronized</font> (resourceA) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">synchronized</font> (resourceB) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> resourceB.value + resourceA.value; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">public</font> <font color="#0000ff">void</font> write(<font color="#0000ff">int</font> a, <font color="#0000ff">int</font> b) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">synchronized</font> (resourceB) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">synchronized</font> (resourceA) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resourceA.value = a; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resourceB.value = b; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;} <br />
}</div>
</div>
<div align="left">&nbsp;</div>
<div align="left">假设read()方法由一个线程启动，write()方法由另外一个线程启动。读线程将拥有resourceA锁，写线程将拥有resourceB锁，两者都坚持等待的话就出现死锁。</div>
<div align="left">&nbsp;</div>
<div align="left">实际上，上面这个例子发生死锁的概率很小。因为在代码内的某个点，CPU必须从读线程切换到写线程，所以，死锁基本上不能发生。</div>
<div align="left">&nbsp;</div>
<div align="left">但是，无论代码中发生死锁的概率有多小，一旦发生死锁，程序就死掉。有一些设计方法能帮助避免死锁，包括始终按照预定义的顺序获取锁这一策略。已经超出SCJP的考试范围。</div>
<div align="left">&nbsp;</div>
<div align="left"><strong>八、线程同步小结</strong></div>
<div align="left">&nbsp;</div>
<div align="left">1、线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。</div>
<div align="left">2、线程同步方法是通过锁来实现，每个对象都有切仅有一个锁，这个锁与一个特定的对象关联，线程一旦获取了对象锁，其他访问该对象的线程就无法再访问该对象的其他非同步方法。</div>
<div align="left">3、对于静态同步方法，锁是针对这个类的，锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获得锁，当在一个同步方法中访问另外对象上的同步方法时，会获取这两个对象锁。</div>
<div align="left">4、对于同步，要时刻清醒在哪个对象上同步，这是关键。</div>
<div align="left">5、编写线程安全的类，需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断，对&#8220;原子&#8221;操作做出分析，并保证原子操作期间别的线程无法访问竞争资源。</div>
<div align="left">6、当多个线程等待一个对象锁时，没有获取到锁的线程将发生阻塞。</div>
<div align="left">7、死锁是线程间相互等待锁锁造成的，在实际中发生的概率非常的小。真让你写个死锁程序，不一定好使，呵呵。但是，一旦程序发生死锁，程序将死掉。</div>
<img src ="http://www.blogjava.net/AntiquMan/aggbug/285349.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AntiquMan/" target="_blank">AntiquMan</a> 2009-07-03 14:45 <a href="http://www.blogjava.net/AntiquMan/archive/2009/07/03/285349.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java多线程编程详解</title><link>http://www.blogjava.net/AntiquMan/archive/2009/03/31/263016.html</link><dc:creator>AntiquMan</dc:creator><author>AntiquMan</author><pubDate>Mon, 30 Mar 2009 17:15:00 GMT</pubDate><guid>http://www.blogjava.net/AntiquMan/archive/2009/03/31/263016.html</guid><wfw:comment>http://www.blogjava.net/AntiquMan/comments/263016.html</wfw:comment><comments>http://www.blogjava.net/AntiquMan/archive/2009/03/31/263016.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AntiquMan/comments/commentRss/263016.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AntiquMan/services/trackbacks/263016.html</trackback:ping><description><![CDATA[<p>一：理解多线程<br />
<br />
多线程是这样一种机制，它允许在程序中并发执行多个指令流，每个指令流都称为一个线程，彼此间互相独立。&nbsp;<br />
<br />
线程又称为轻量级进程，它和进程一样拥有独立的执行控制，由操作系统负责调度，区别在于线程没有独立的存储空间，而是和所属进程中的其它线程共享一个存储空间，这使得线程间的通信远较进程简单。<br />
<br />
多个线程的执行是并发的，也就是在逻辑上&#8220;同时&#8221;，而不管是否是物理上的&#8220;同时&#8221;。如果系统只有一个CPU，那么真正的&#8220;同时&#8221;是不可能的，但是由于CPU的速度非常快，用户感觉不到其中的区别，因此我们也不用关心它，只需要设想各个线程是同时执行即可。<br />
<br />
多线程和传统的单线程在程序设计上最大的区别在于，由于各个线程的控制流彼此独立，使得各个线程之间的代码是乱序执行的，由此带来的线程调度，同步等问题，将在以后探讨。<br />
<br />
<strong>二：在Java中实现多线程</strong><br />
<br />
我们不妨设想，为了创建一个新的线程，我们需要做些什么？很显然，我们必须指明这个线程所要执行的代码，而这就是在Java中实现多线程我们所需要做的一切！<br />
<br />
真是神奇！Java是如何做到这一点的？通过类！作为一个完全面向对象的语言，Java提供了类&nbsp;java.lang.Thread&nbsp;来方便多线程编程，这个类提供了大量的方法来方便我们控制自己的各个线程，我们以后的讨论都将围绕这个类进行。&nbsp;<br />
<br />
那么如何提供给&nbsp;Java&nbsp;我们要线程执行的代码呢？让我们来看一看&nbsp;Thread&nbsp;类。Thread&nbsp;类最重要的方法是&nbsp;run()&nbsp;，它为Thread&nbsp;类的方法&nbsp;start()&nbsp;所调用，提供我们的线程所要执行的代码。为了指定我们自己的代码，只需要覆盖它！<br />
<br />
方法一：继承&nbsp;Thread&nbsp;类，覆盖方法&nbsp;run()<br />
<br />
我们在创建的&nbsp;Thread&nbsp;类的子类中重写&nbsp;run()&nbsp;,加入线程所要执行的代码即可。<br />
下面是一个例子：</p>
<blockquote><span>CODE:</span>
<hr />
<pre><br />
public&nbsp;class&nbsp;MyThread&nbsp;extends&nbsp;Thread&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[])&nbsp;<br />
<br />
}<br />
</pre>
<hr />
</blockquote>
<p><br />
<br />
这种方法简单明了，符合大家的习惯，但是，它也有一个很大的缺点，那就是如果我们的类已经从一个类继承（如小程序必须继承自&nbsp;Applet&nbsp;类），则无法再继承&nbsp;Thread&nbsp;类，这时如果我们又不想建立一个新的类，应该怎么办呢？<br />
<br />
我们不妨来探索一种新的方法：我们不创建&nbsp;Thread&nbsp;类的子类，而是直接使用它，那么我们只能将我们的方法作为参数传递给&nbsp;Thread&nbsp;类的实例，有点类似回调函数。但是&nbsp;Java&nbsp;没有指针，我们只能传递一个包含这个方法的类的实例。那么如何限制这个类必须包含这一方法呢？当然是使用接口！（虽然抽象类也可满足，但是需要继承，而我们之所以要采用这种新方法，不就是为了避免继承带来的限制吗？）<br />
<br />
<br />
Java&nbsp;提供了接口&nbsp;java.lang.Runnable&nbsp;来支持这种方法。<br />
<br />
方法二：实现&nbsp;Runnable&nbsp;接口<br />
<br />
<br />
Runnable&nbsp;接口只有一个方法&nbsp;run()，我们声明自己的类实现&nbsp;Runnable&nbsp;接口并提供这一方法，将我们的线程代码写入其中，就完成了这一部分的任务。<br />
<br />
但是&nbsp;Runnable&nbsp;接口并没有任何对线程的支持，我们还必须创建&nbsp;Thread&nbsp;类的实例，这一点通过&nbsp;Thread&nbsp;类的构造函数<br />
public&nbsp;Thread(Runnable&nbsp;target);来实现。<br />
<br />
下面是一个例子：</p>
<blockquote><span>CODE:</span>
<hr />
<pre><br />
public&nbsp;class&nbsp;MyThread&nbsp;implements&nbsp;Runnable&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[])&nbsp;<br />
<br />
}<br />
</pre>
<hr />
</blockquote>
<p><br />
<br />
严格地说，创建&nbsp;Thread&nbsp;子类的实例也是可行的，但是必须注意的是，该子类必须没有覆盖&nbsp;Thread&nbsp;类的&nbsp;run&nbsp;方法，否则该线程执行的将是子类的&nbsp;run&nbsp;方法，而不是我<br />
<br />
们用以实现Runnable&nbsp;接口的类的&nbsp;run&nbsp;方法，对此大家不妨试验一下。<br />
<br />
使用&nbsp;Runnable&nbsp;接口来实现多线程使得我们能够在一个类中包容所有的代码，有利于封装，它的缺点在于，我们只能使用一套代码，若想创建多个线程并使各个线程执行不同的代码，则仍必须额外创建类，如果这样的话，在大多数情况下也许还不如直接用多个类分别继承&nbsp;Thread&nbsp;来得紧凑。<br />
<br />
<br />
综上所述，两种方法各有千秋，大家可以灵活运用。<br />
<br />
下面让我们一起来研究一下多线程使用中的一些问题。<br />
<br />
<strong>三：线程的四种状态</strong><br />
<br />
1.&nbsp;新状态：线程已被创建但尚未执行（start()&nbsp;尚未被调用）。<br />
<br />
2.&nbsp;可执行状态：线程可以执行，虽然不一定正在执行。CPU&nbsp;时间随时可能被分配给该线程，从而使得它执行。<br />
<br />
3.&nbsp;死亡状态：正常情况下&nbsp;run()&nbsp;返回使得线程死亡。调用&nbsp;stop()或&nbsp;destroy()&nbsp;亦有同样效果，但是不被推荐，前者会产生异常，后者是强制终止，不会释放锁。<br />
<br />
4.&nbsp;阻塞状态：线程不会被分配&nbsp;CPU&nbsp;时间，无法执行。<br />
<br />
<strong>四：线程的优先级&nbsp;</strong><br />
<br />
线程的优先级代表该线程的重要程度，当有多个线程同时处于可执行状态并等待获得&nbsp;CPU&nbsp;时间时，线程调度系统根据各个线程的优先级来决定给谁分配&nbsp;CPU&nbsp;时间，优先级高的线程有更大的机会获得&nbsp;CPU&nbsp;时间，优先级低的线程也不是没有机会，只是机会要小一些罢了。<br />
<br />
<br />
你可以调用&nbsp;Thread&nbsp;类的方法&nbsp;getPriority()&nbsp;和&nbsp;setPriority()来存取线程的优先级，线程的优先级界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之间，缺省是5(NORM_PRIORITY)。<br />
<br />
<br />
<strong>五：线程的同步</strong><br />
<br />
由于同一进程的多个线程共享同一片存储空间，在带来方便的同时，也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突，有效避免了同一个数据对象被多个线程同时访问。<br />
<br />
<br />
由于我们可以通过&nbsp;private&nbsp;关键字来保证数据对象只能被方法访问，所以我们只需针对方法提出一套机制，这套机制就是&nbsp;synchronized&nbsp;关键字，它包括两种用法：synchronized&nbsp;方法和&nbsp;synchronized&nbsp;块。<br />
<br />
<br />
<br />
1.&nbsp;synchronized&nbsp;方法：通过在方法声明中加入&nbsp;synchronized关键字来声明&nbsp;synchronized&nbsp;方法。如：<br />
<br />
public&nbsp;synchronized&nbsp;void&nbsp;accessVal(int&nbsp;newVal);<br />
<br />
<br />
synchronized&nbsp;方法控制对类成员变量的访问：每个类实例对应一把锁，每个&nbsp;synchronized&nbsp;方法都必须获得调用该方法的类实例的锁方能执行，否则所属线程阻塞，方<br />
<br />
法一旦执行，就独占该锁，直到从该方法返回时才将锁释放，此后被阻塞的线程方能获得该锁，重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例，其所有声明为&nbsp;synchronized&nbsp;的成员函数中至多只有一个处于可执行状态（因为至多只有一个能够获得该类实例对应的锁），从而有效避免了类成员变量的访问冲突（只要所有可能访问类成员变量的方法均被声明为&nbsp;synchronized）。<br />
<br />
<br />
在&nbsp;Java&nbsp;中，不光是类实例，每一个类也对应一把锁，这样我们也可将类的静态成员函数声明为&nbsp;synchronized&nbsp;，以控制其对类的静态成员变量的访问。<br />
synchronized&nbsp;方法的缺陷：若将一个大的方法声明为synchronized&nbsp;将会大大影响效率，典型地，若将线程类的方法&nbsp;run()&nbsp;声明为&nbsp;synchronized&nbsp;，由于在线程的整个生命期内它一直在运行，因此将导致它对本类任何&nbsp;synchronized&nbsp;方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中，将其声明为&nbsp;synchronized&nbsp;，并在主方法中调用来解决这一问题，但是&nbsp;Java&nbsp;为我们提供了更好的解决办法，那就是&nbsp;synchronized&nbsp;块。<br />
<br />
2.&nbsp;synchronized&nbsp;块：通过&nbsp;synchronized关键字来声明synchronized&nbsp;块。语法如下：&nbsp;<br />
synchronized(syncObject)&nbsp;<br />
<br />
<br />
<br />
synchronized&nbsp;块是这样一个代码块，其中的代码必须获得对象&nbsp;syncObject&nbsp;（如前所述，可以是类实例或类）的锁方能执行，具体机制同前所述。由于可以针对任意代码块，且可任意指定上锁的对象，故灵活性较高。<br />
<br />
<br />
<br />
<strong>六：线程的阻塞</strong><br />
<br />
<br />
<br />
为了解决对共享存储区的访问冲突，Java&nbsp;引入了同步机制，现在让我们来考察多个线程对共享资源的访问，显然同步机制已经不够了，因为在任意时刻所要求的资源不一定已经准备好了被访问，反过来，同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题，Java&nbsp;引入了对阻塞机制的支持。<br />
<br />
<br />
阻塞指的是暂停一个线程的执行以等待某个条件发生（如某资源就绪），学过操作系统的同学对它一定已经很熟悉了。Java&nbsp;提供了大量方法来支持阻塞，下面让我们逐一分析。<br />
<br />
<br />
<br />
1.&nbsp;sleep()&nbsp;方法：sleep()&nbsp;允许&nbsp;指定以毫秒为单位的一段时间作为参数，它使得线程在指定的时间内进入阻塞状态，不能得到CPU&nbsp;时间，指定的时间一过，线程重新进入可执行状态。<br />
<br />
典型地，sleep()&nbsp;被用在等待某个资源就绪的情形：测试发现条件不满足后，让线程阻塞一段时间后重新测试，直到条件满足为止。<br />
<br />
<br />
2.&nbsp;suspend()&nbsp;和&nbsp;resume()&nbsp;方法：两个方法配套使用，suspend()使得线程进入阻塞状态，并且不会自动恢复，必须其对应的resume()&nbsp;被调用，才能使得线程重新进入可执行状态。典型地，suspend()&nbsp;和&nbsp;resume()&nbsp;被用在等待另一个线程产生的结果的情形：测试发现结果还没有产生后，让线程阻塞，另一个线程产生了结果后，调用&nbsp;resume()&nbsp;使其恢复。<br />
<br />
<br />
3.&nbsp;yield()&nbsp;方法：yield()&nbsp;使得线程放弃当前分得的&nbsp;CPU&nbsp;时间，但是不使线程阻塞，即线程仍处于可执行状态，随时可能再次分得&nbsp;CPU&nbsp;时间。调用&nbsp;yield()&nbsp;的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。<br />
<br />
<br />
<br />
4.&nbsp;wait()&nbsp;和&nbsp;notify()&nbsp;方法：两个方法配套使用，wait()&nbsp;使得线程进入阻塞状态，它有两种形式，一种允许&nbsp;指定以毫秒为单位的一段时间作为参数，另一种没有参数，前者当对应的&nbsp;notify()&nbsp;被调用或者超出指定时间时线程重新进入可执行状态，后者则必须对应的&nbsp;notify()&nbsp;被调用。<br />
<br />
初看起来它们与&nbsp;suspend()&nbsp;和&nbsp;resume()&nbsp;方法对没有什么分别，但是事实上它们是截然不同的。区别的核心在于，前面叙述的所有方法，阻塞时都不会释放占用的锁（如果占用了的话），而这一对方法则相反。<br />
<br />
<br />
<br />
上述的核心区别导致了一系列的细节上的区别。<br />
<br />
首先，前面叙述的所有方法都隶属于&nbsp;Thread&nbsp;类，但是这一对却直接隶属于&nbsp;Object&nbsp;类，也就是说，所有对象都拥有这一对方法。初看起来这十分不可思议，但是实际上却是很自然的，因为这一对方法阻塞时要释放占用的锁，而锁是任何对象都具有的，调用任意对象的&nbsp;wait()&nbsp;方法导致线程阻塞，并且该对象上的锁被释放。而调用&nbsp;任意对象的notify()方法则导致因调用该对象的&nbsp;wait()&nbsp;方法而阻塞的线程中随机选择的一个解除阻塞（但要等到获得锁后才真正可执行）。<br />
<br />
其次，前面叙述的所有方法都可在任何位置调用，但是这一对方法却必须在&nbsp;synchronized&nbsp;方法或块中调用，理由也很简单，只有在synchronized&nbsp;方法或块中当前线程才占有锁，才有锁可以释放。同样的道理，调用这一对方法的对象上的锁必须为当前线程所拥有，这样才有锁可以释放。因此，这一对方法调用必须放置在这样的&nbsp;synchronized&nbsp;方法或块中，该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件，则程序虽然仍能编译，但在运行时会出现IllegalMonitorStateException&nbsp;异常。<br />
<br />
<br />
<br />
wait()&nbsp;和&nbsp;notify()&nbsp;方法的上述特性决定了它们经常和synchronized&nbsp;方法或块一起使用，将它们和操作系统的进程间通信机制作一个比较就会发现它们的相似性：synchronized方法或块提供了类似于操作系统原语的功能，它们的执行不会受到多线程机制的干扰，而这一对方法则相当于&nbsp;block&nbsp;和wakeup&nbsp;原语（这一对方法均声明为&nbsp;synchronized）。它们的结合使得我们可以实现操作系统上一系列精妙的进程间通信的算法（如信号量算法），并用于解决各种复杂的线程间通信问题。<br />
<br />
<br />
<br />
关于&nbsp;wait()&nbsp;和&nbsp;notify()&nbsp;方法最后再说明两点：<br />
<br />
第一：调用&nbsp;notify()&nbsp;方法导致解除阻塞的线程是从因调用该对象的&nbsp;wait()&nbsp;方法而阻塞的线程中随机选取的，我们无法预料哪一个线程将会被选择，所以编程时要特别小心，避免因这种不确定性而产生问题。<br />
<br />
第二：除了&nbsp;notify()，还有一个方法&nbsp;notifyAll()&nbsp;也可起到类似作用，唯一的区别在于，调用&nbsp;notifyAll()&nbsp;方法将把因调用该对象的&nbsp;wait()&nbsp;方法而阻塞的所有线程一次性全部解除阻塞。当然，只有获得锁的那一个线程才能进入可执行状态。<br />
<br />
<br />
<br />
谈到阻塞，就不能不谈一谈死锁，略一分析就能发现，suspend()&nbsp;方法和不指定超时期限的&nbsp;wait()&nbsp;方法的调用都可能产生死锁。遗憾的是，Java&nbsp;并不在语言级别上支持死锁的避免，我们在编程中必须小心地避免死锁。<br />
<br />
<br />
<br />
以上我们对&nbsp;Java&nbsp;中实现线程阻塞的各种方法作了一番分析，我们重点分析了&nbsp;wait()&nbsp;和&nbsp;notify()&nbsp;方法，因为它们的功能最强大，使用也最灵活，但是这也导致了它们的效率较低，较容易出错。实际使用中我们应该灵活使用各种方法，以便更好地达到我们的目的。<br />
<br />
<br />
<br />
<strong>七：守护线程</strong><br />
<br />
<br />
<br />
守护线程是一类特殊的线程，它和普通线程的区别在于它并不是应用程序的核心部分，当一个应用程序的所有非守护线程终止运行时，即使仍然有守护线程在运行，应用程序也将终止，反之，只要有一个非守护线程在运行，应用程序就不会终止。守护线程一般被用于在后台为其它线程提供服务。<br />
<br />
<br />
可以通过调用方法&nbsp;isDaemon()&nbsp;来判断一个线程是否是守护线程，也可以调用方法&nbsp;setDaemon()&nbsp;来将一个线程设为守护线程。<br />
<br />
<br />
<br />
<strong>八：线程组</strong><br />
<br />
<br />
<br />
线程组是一个&nbsp;Java&nbsp;特有的概念，在&nbsp;Java&nbsp;中，线程组是类ThreadGroup&nbsp;的对象，每个线程都隶属于唯一一个线程组，这个线程组在线程创建时指定并在线程的整个生命期内都不能更改。你可以通过调用包含&nbsp;ThreadGroup&nbsp;类型参数的&nbsp;Thread&nbsp;类构造函数来指定线程属的线程组，若没有指定，则线程缺省地隶属于名为&nbsp;system&nbsp;的系统线程组。<br />
<br />
<br />
在&nbsp;Java&nbsp;中，除了预建的系统线程组外，所有线程组都必须显式创建。<br />
<br />
<br />
<br />
在&nbsp;Java&nbsp;中，除系统线程组外的每个线程组又隶属于另一个线程组，你可以在创建线程组时指定其所隶属的线程组，若没有指定，则缺省地隶属于系统线程组。这样，所有线程组组成了一棵以系统线程组为根的树。<br />
<br />
<br />
Java&nbsp;允许我们对一个线程组中的所有线程同时进行操作，比如我们可以通过调用线程组的相应方法来设置其中所有线程的优先级，也可以启动或阻塞其中的所有线程。<br />
<br />
<br />
<br />
Java&nbsp;的线程组机制的另一个重要作用是线程安全。线程组机制允许我们通过分组来区分有不同安全特性的线程，对不同组的线程进行不同的处理，还可以通过线程组的分层结构来支持不对等安全措施的采用。Java&nbsp;的&nbsp;ThreadGroup&nbsp;类提供了大量的方法来方便我们对线程组树中的每一个线程组以及线程组中的每一个线程进行操作。<br />
<br />
<br />
<br />
<strong>九：总结</strong><br />
<br />
<br />
<br />
在这一讲中，我们一起学习了&nbsp;Java&nbsp;多线程编程的方方面面，包括创建线程，以及对多个线程进行调度、管理。我们深刻认识到了多线程编程的复杂性，以及线程切换开销带来的多线程程序的低效性，这也促使我们认真地思考一个问题：我们是否需要多线程？何时需要多线程？<br />
<br />
<br />
多线程的核心在于多个代码块并发执行，本质特点在于各代码块之间的代码是乱序执行的。我们的程序是否需要多线程，就是要看这是否也是它的内在特点。<br />
<br />
<br />
<br />
假如我们的程序根本不要求多个代码块并发执行，那自然不需要使用多线程；假如我们的程序虽然要求多个代码块并发执行，但是却不要求乱序，则我们完全可以用一个循环来简单高效地实现，也不需要使用多线程；只有当它完全符合多线程的特点时，多线程机制对线程间通信和线程管理的强大支持才能有用武之地，这时使用多线程才是值得的。&nbsp;</p>
 <img src ="http://www.blogjava.net/AntiquMan/aggbug/263016.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AntiquMan/" target="_blank">AntiquMan</a> 2009-03-31 01:15 <a href="http://www.blogjava.net/AntiquMan/archive/2009/03/31/263016.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>