﻿<?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-Jiangshachina-随笔分类-Concurrency</title><link>http://www.blogjava.net/jiangshachina/category/26908.html</link><description>同是Java爱好者，相逢何必曾相识！&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;a cup of Java, cheers!</description><language>zh-cn</language><lastBuildDate>Tue, 22 Apr 2014 11:06:28 GMT</lastBuildDate><pubDate>Tue, 22 Apr 2014 11:06:28 GMT</pubDate><ttl>60</ttl><item><title>Java并发基础实践--死锁(原)</title><link>http://www.blogjava.net/jiangshachina/archive/2013/12/29/408180.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Sun, 29 Dec 2013 12:19:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2013/12/29/408180.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/408180.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2013/12/29/408180.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/408180.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/408180.html</trackback:ping><description><![CDATA[<div><div align="center"><strong><span style="font-size: 14pt;">Java并发基础实践--死锁</span></strong></div>本文是<a href="http://www.blogjava.net/jiangshachina/category/53896.html">Java并发基础实践</a>系列中的一篇，介绍了最简单的死锁场景，并使用jstack产生的thread dump来查找死锁。(2013.12.29最后更新)<br /><br /><strong style="font-size: 12pt;">1. 死锁</strong><br style="font-size: 12pt;" />为了能够维护线程的安全性，Java提供的锁机制，但不恰当地使用锁则可能产生死锁。死锁是并发编程中一个无法绕开的问题。只要在一个任务中使用了一个以上的锁，那么就存在死锁的风险。<br />死锁产生的直接原因非常简单，即两个线程在相互等待对方所执有的锁。<br /><br /><strong><span style="font-size: 12pt;">2. 锁顺序死锁</span></strong><br />在死锁场景中，最典型的就是锁顺序死锁，代码清单1就是一个很常见的示例。<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单1</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;DeadLock&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;Object&nbsp;leftLock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Object();<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;Object&nbsp;rightLock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Object();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;leftRight()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">synchronized</span><span style="color: #000000; ">&nbsp;(leftLock)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">3</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<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 /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">synchronized</span><span style="color: #000000; ">&nbsp;(rightLock)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">leftRight</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<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;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;rightLeft()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">synchronized</span><span style="color: #000000; ">&nbsp;(rightLock)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">3</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<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 /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">synchronized</span><span style="color: #000000; ">&nbsp;(leftLock)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">leftRight</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<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;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;DeadLock&nbsp;deadLock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;DeadLock();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;t1&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Runnable()&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deadLock.leftRight();<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&nbsp;t2&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Runnable()&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deadLock.rightLeft();<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;t1.start();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2.start();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><br /><strong><span style="font-size: 12pt;">3. Thread Dump</span></strong><br />JDK提供了一组命令行工具，其中就包括jstack。通过jstack可以获取当前正运行的Java进程的java stack和native stack信息。如果Java进程崩溃了，也可以通过它来获取core file中的java stack和native stack信息，以方便我们定位问题。<br />为了能够使用jstack去输出目标Java进程的thread dump，首先必须要弄清楚在执行清单1的程序时，该程序的进程号。JDK提供的另一个命令行工具jps可以获取系统中所有Java进程的相关信息。<br />在命令行窗口中执行命令<em>jps</em>，即可以得到清单2所示的结果<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单2</em><br />C:\Documents&nbsp;and&nbsp;Settings\Administrator&gt;jps<br /></span><span style="color: #000000; ">2848</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">4552</span><span style="color: #000000; ">&nbsp;DeadLock<br /></span><span style="color: #000000; ">5256</span><span style="color: #000000; ">&nbsp;Jps</span></div>其中<em>4552</em>就是在笔者机器上执行程序DeadLock时所生成Java进程的进程号。<br />然后再执行命令<em>jstack 4552</em>，在笔者的机器上就会得到清单3所示的结果<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单3</em><br />C:\Documents&nbsp;and&nbsp;Settings\Administrator&gt;jstack&nbsp;</span><span style="color: #000000; ">4552</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">2013</span><span style="color: #000000; ">-</span><span style="color: #000000; ">12</span><span style="color: #000000; ">-</span><span style="color: #000000; ">29</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">18</span><span style="color: #000000; ">:</span><span style="color: #000000; ">45</span><span style="color: #000000; ">:</span><span style="color: #000000; ">41</span><span style="color: #000000; "><br />Full&nbsp;thread&nbsp;dump&nbsp;Java&nbsp;HotSpot(TM)&nbsp;Client&nbsp;VM&nbsp;(</span><span style="color: #000000; ">23.25</span><span style="color: #000000; ">-b01&nbsp;mixed&nbsp;mode</span><span style="color: #000000; ">,</span><span style="color: #000000; ">&nbsp;sharing):<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">DestroyJavaVM</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">6</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x00878800&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0xd00&nbsp;waiting&nbsp;on&nbsp;condition&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x00000000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;RUNNABLE<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">6</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b56c00&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x14ec&nbsp;waiting&nbsp;for&nbsp;monitor&nbsp;entry&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x02fdf000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;BLOCKED&nbsp;(on&nbsp;object&nbsp;monitor)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:</span><span style="color: #000000; ">33</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;&lt;0x22be6598&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22be65a0&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock$</span><span style="color: #000000; ">2</span><span style="color: #000000; ">.run(DeadLock.java:</span><span style="color: #000000; ">53</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000; ">724</span><span style="color: #000000; ">)<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">6</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b55c00&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x354&nbsp;waiting&nbsp;for&nbsp;monitor&nbsp;entry&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x02f8f000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;BLOCKED&nbsp;(on&nbsp;object&nbsp;monitor)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock.leftRight(DeadLock.java:</span><span style="color: #000000; ">19</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;&lt;0x22be65a0&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22be6598&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock$</span><span style="color: #000000; ">1</span><span style="color: #000000; ">.run(DeadLock.java:</span><span style="color: #000000; ">45</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000; ">724</span><span style="color: #000000; ">)<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Service&nbsp;Thread</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;daemon&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">6</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b34800&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x133c&nbsp;runnable&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x00000000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;RUNNABLE<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">C1&nbsp;CompilerThread0</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;daemon&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b13800&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x10fc&nbsp;waiting&nbsp;on&nbsp;condition&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x00000000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;RUNNABLE<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Attach&nbsp;Listener</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;daemon&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b11c00&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x1424&nbsp;waiting&nbsp;on&nbsp;condition&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x00000000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;RUNNABLE<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Signal&nbsp;Dispatcher</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;daemon&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b10800&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x1100&nbsp;runnable&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x00000000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;RUNNABLE<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Finalizer</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;daemon&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">8</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02af4c00&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x1238&nbsp;in&nbsp;Object.wait()&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x02daf000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;WAITING&nbsp;(on&nbsp;object&nbsp;monitor)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Object.wait(Native&nbsp;Method)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;on&nbsp;&lt;0x22b60fb8&gt;&nbsp;(a&nbsp;java.lang.ref.ReferenceQueue$Lock)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:</span><span style="color: #000000; ">135</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22b60fb8&gt;&nbsp;(a&nbsp;java.lang.ref.ReferenceQueue$Lock)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:</span><span style="color: #000000; ">151</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:</span><span style="color: #000000; ">189</span><span style="color: #000000; ">)<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Reference&nbsp;Handler</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;daemon&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02af0000&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x12e8&nbsp;in&nbsp;Object.wait()&nbsp;</span><span style="color: #800000; font-weight: bold; ">[</span><span style="color: #800000; ">0x02d5f000</span><span style="color: #800000; font-weight: bold; ">]</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;java.lang.Thread.State:&nbsp;WAITING&nbsp;(on&nbsp;object&nbsp;monitor)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Object.wait(Native&nbsp;Method)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;on&nbsp;&lt;0x22b60da0&gt;&nbsp;(a&nbsp;java.lang.ref.Reference$Lock)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Object.wait(Object.java:</span><span style="color: #000000; ">503</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.ref.Reference$ReferenceHandler.run(Reference.java:</span><span style="color: #000000; ">133</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22b60da0&gt;&nbsp;(a&nbsp;java.lang.ref.Reference$Lock)<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">VM&nbsp;Thread</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02aee400&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x129c&nbsp;runnable<br /><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">VM&nbsp;Periodic&nbsp;Task&nbsp;Thread</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;prio</span><span style="color: #000000; ">=</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;tid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x02b48000&nbsp;nid</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0x89c&nbsp;waiting&nbsp;on&nbsp;condition<br /><br />JNI&nbsp;global&nbsp;references:&nbsp;</span><span style="color: #000000; ">117</span><span style="color: #000000; "><br /><br /><br />Found&nbsp;one&nbsp;Java-level&nbsp;deadlock:<br /></span><span style="color: #000000; ">=============================</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;monitor&nbsp;0x02af4a3c&nbsp;(object&nbsp;0x22be6598</span><span style="color: #000000; ">,</span><span style="color: #000000; ">&nbsp;a&nbsp;java.lang.Object)</span><span style="color: #000000; ">,</span><span style="color: #000000; "><br />&nbsp;&nbsp;which&nbsp;is&nbsp;held&nbsp;by&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;monitor&nbsp;0x02af310c&nbsp;(object&nbsp;0x22be65a0</span><span style="color: #000000; ">,</span><span style="color: #000000; ">&nbsp;a&nbsp;java.lang.Object)</span><span style="color: #000000; ">,</span><span style="color: #000000; "><br />&nbsp;&nbsp;which&nbsp;is&nbsp;held&nbsp;by&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /><br />Java&nbsp;stack&nbsp;information&nbsp;for&nbsp;the&nbsp;threads&nbsp;listed&nbsp;above:<br /></span><span style="color: #000000; ">===================================================</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:</span><span style="color: #000000; ">33</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;&lt;0x22be6598&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22be65a0&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock$</span><span style="color: #000000; ">2</span><span style="color: #000000; ">.run(DeadLock.java:</span><span style="color: #000000; ">53</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000; ">724</span><span style="color: #000000; ">)<br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock.leftRight(DeadLock.java:</span><span style="color: #000000; ">19</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;&lt;0x22be65a0&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22be6598&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock$</span><span style="color: #000000; ">1</span><span style="color: #000000; ">.run(DeadLock.java:</span><span style="color: #000000; ">45</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000; ">724</span><span style="color: #000000; ">)<br /><br />Found&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;deadlock.</span></div>在上述输出中，我们可以很明确地看到一个死锁<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;monitor&nbsp;0x02af4a3c&nbsp;(object&nbsp;0x22be6598</span><span style="color: #000000; ">,</span><span style="color: #000000; ">&nbsp;a&nbsp;java.lang.Object)</span><span style="color: #000000; ">,</span><span style="color: #000000; "><br />&nbsp;&nbsp;which&nbsp;is&nbsp;held&nbsp;by&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;monitor&nbsp;0x02af310c&nbsp;(object&nbsp;0x22be65a0</span><span style="color: #000000; ">,</span><span style="color: #000000; ">&nbsp;a&nbsp;java.lang.Object)</span><span style="color: #000000; ">,</span><span style="color: #000000; "><br />&nbsp;&nbsp;which&nbsp;is&nbsp;held&nbsp;by&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span></div>并且它还标明了程序是在哪个地方时发现了上述死锁<br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:</span><span style="color: #000000; ">33</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;&lt;0x22be6598&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22be65a0&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock$</span><span style="color: #000000; ">2</span><span style="color: #000000; ">.run(DeadLock.java:</span><span style="color: #000000; ">53</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000; ">724</span><span style="color: #000000; ">)<br /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">Thread-0</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock.leftRight(DeadLock.java:</span><span style="color: #000000; ">19</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;&lt;0x22be65a0&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;locked&nbsp;&lt;0x22be6598&gt;&nbsp;(a&nbsp;java.lang.Object)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;concurrency.deadlock.DeadLock$</span><span style="color: #000000; ">1</span><span style="color: #000000; ">.run(DeadLock.java:</span><span style="color: #000000; ">45</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000; ">724</span><span style="color: #000000;">)</span></div><br /><strong><span style="font-size: 12pt;">4. 小结</span></strong><br />死锁产生的直接原因非常简单，即两个线程在相互等待对方所执有的锁。锁顺序死锁是其中最经典的场景，此外还有动态的锁顺序死锁。虽然表现形式有所不同，但本质上都是两个线程在以不同的顺序来获取相同锁时，发生了死锁问题。<br />使用thread dump可以帮助我们分析死锁产生的原因。除了直接使用jstack命令来获取thread dump输出以外，JDK还提供了jvisualvm工具，它能以可视化的方式展示Java程序的进程号并导出thread dump。</div><img src ="http://www.blogjava.net/jiangshachina/aggbug/408180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2013-12-29 20:19 <a href="http://www.blogjava.net/jiangshachina/archive/2013/12/29/408180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Concurrent Animated(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2013/12/07/407310.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Sat, 07 Dec 2013 09:45:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2013/12/07/407310.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/407310.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2013/12/07/407310.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/407310.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/407310.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt;"> </span><div><div align="center"><strong><span style="font-size: 14pt;">Java Concurrent Animated</span></strong></div><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 在最新一期的<a href="http://www.oracle.com/technetwork/java/javamagazine/index.html">Java Magazine</a>中有一篇访谈，介绍了一个学习Java并发编程的动画应用<a href="http://sourceforge.net/projects/javaconcurrenta/">Java Concurrent Animated</a>。该应用以十分直观的方式展示了Java并发工具包中的每一个重要组件，降低了学习Java并发编程的难度。(2013.12.07最后更新)</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：有多少人已经试用过了你的Java Concurrent Animated应用？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：该应用是在2009年7月被引入的，从那时算起，已经有了大约20000的下载量。但考虑到已有约一千万的Java开发者，这个下载量才只是开始。按国家区分，下载最多的分别是美国(23%)，印度(14)和中国(7%)。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 你可以下载一个可以执行的JAR文件，然后仅需双击它就可以运行了。该应用是由菜单驱动的，或者也可以使用向上或向下键在不同的图像和动画之间进行导航。它能运行在诸如Windows，Mac，Linux等等所有的平台上。它要求安装Java SE 6或更高的版本。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：对这个应用最典型的反馈是什么？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：大家告诉我这个工具很好用。许多人确实对此感到兴奋，尤其是那些正试图向团队教授合适并发技术的老师与领导们。Java是最早在核心类库中引入并发的语言之一。在当时，这是一个很强大的特性，但我们很快就发现一个非常优秀的程序员与会写出很糟糕的并发代码。进行恰当的并发编程是一件困难甚至是不可能的事情，但是如何人们能花些时间去理解一些现有的框架，那么在进行并发编码时所产生潜在错误就会变得极少。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 例如，去看看Java内存模型。开发者经常忽视Java内存模型，而像个幸福的傻瓜一样在编码，那么他们的程序会不太正常，因为Java虚拟机(JVM)和服务器可能无法利用到由Java内存模型所提供的优化。由于内核在速度与数量上都有了增长，厂商们期望能够高效地利用到这些内核，然而由于错误的并发管理，本来如期运行的程序却开始遇到了一些零星的错误。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：你是说，这个应用会以我们所虚构的方式去使开发者们能够更快且直观地掌握Java并发的原理与实践？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：那是达到这一目的一个有趣的途径。你知道的，Java Concurrent Animated并不是一个Flash动画。它是一组可交互的Java程序，也即，每个动画都是真地在使用它所要演示的并发组件。在屏幕的右边是一个展示代码片断的面板，由于动画的运行，它会动态地高亮显示及恢复正在执行的代码。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 让你给你一个例子，这个例子发生在ReadWriteLock这个动画中。ReadWriteLock用于确保数据的一致性。它允许不受数量限制的线程去获取读锁，并能并发地对这个锁进行操作。但是，写线程在获取这个锁之前只能等待所有的读线程执行结束。一旦一个写线程获得了这个锁，那么其它的读线程或写线程将无法获取它。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 假设一个写线程正在等待正在执行中的读线程去释放这个读锁，但突然一个新的读线程跑过来了。那么谁应该获得这个锁会比较好呢？这个新的读线程应该跑到写线程前面去吗？毕竟，如果其它的读线程已经获得了这个锁，那么新来的读线程为什么要去等一个尚在等待中的写线程呢？而这实际上这正是Java 5所干的事儿。但某次我在Java 6上运行这个动画时，我注意到行为发生了改变。即，随后而来的读线程在获取到这个锁之前可能要等待所有的写线程先释放锁。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 我认为这个新的行为是一个BUG，且向并发专家Heinz Kabutz博士提及了此事。博士解释道，这不是一个错误，而一个特性。如果允许新到的读线程跳到正处于等待中的写线程的前面去，这就存在产生线程饥饿条件的高风险。因为，存在一种很大的可能性，可能没有任何写线程能获得这个锁，它们将永远等待着。这就是一个如何使用动画去警示依赖于JVM运行时版本的线程行为的例子。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：以动画教程的形式来展示特殊值，在Java并发编程中有何与众不同吗？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：Miller定律教会我们，我们的大脑在某一时刻能处理的思维的数量是有限的。人类大脑倾向于进行顺序的思维处理，那么即便我们能够克服身体上的束缚，并能够去正确地进行理解，在以后也很难返回至前去重新构造前面的思维处理。可以肯定地是，如果另一个开发者在以后能深入对其进行研究，那么仍然非常难以从原有的思维成果中再次捕捉到认知轨迹。这样的话，脆弱的代码就会很突然地不能正常工作了。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 通过使用框架，我们不仅将并发编程委托给了创建和维护该框架的聪明开发者们，而且还为沟通设计时引入了一个词典。所以，我可以说，&#8220;下面的代码会当作CyclicBarrier去执行&#8221;，而人们会明白那是什么意思。通过为java.util.concurrent中的所有组件都引入一个可交互化的动画应用，开发者们点着鼠标就能很方便地将他们所探究的功能进行可视化，使理解这些算法变得真心简单了。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：你当时正在研究某些直觉，这些直觉可以帮助更方便地学习并发编程。从开发者的反馈来看，这些直觉看起来是有效的。</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：是的。例如，我前面解释的ReadWriteLock基本功能。读者们可能理解了，也可能没有。现在让我们看看这个与其有关的动画，如图表1所示。</span><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/jiangshachina/JAC/JCA_01.PNG" height="568" width="872" /><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 绿色线程是读线程，最上面的白色线程(带着菱形箭头)是一个写线程，它下面的白色线程是一个新的读线程，该线程在获取锁之前必须要等待所有的读线程与写线程执行完毕。如果你点击按钮并观看这些动画，会比通过浏览繁冗的解释性文字去进行理解要简单得多了。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：Heinz Kabutz评论道，Java被构建成能够一次性做许多事情，而这正与并发完全相关。你的学习系统是如何提高程序员的技能，以便他们能降低并发错误的风险。</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：经常地，当我要努力克服一个并发问题时，我知道解决方案就存在于某个设计模式中，但是哪一个呢？在开发者探寻一个正确解决方案时，Java Concurrent Animated为他们提供了一个所有方案的目录；在激发出正确方案的过程中，它扮演着向导的角色。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：当你管理的团队正在使用Java并发，并且你和你的团队都想更好地去理解Java并发，Java Concurrent Animated有着它的出发点。是什么导致你使用动画呢，能描述下这个过程吗？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：我的培训是针对投资部门的服务器端Java应用，在那里，并发是一个通常都会受到关注的问题。交易员们要求延迟要低，这样可以确保他们在这个需要于一毫秒窗口时间内捕捉交易机会的比赛中不会成为失败者。批量处理也要求快速完成，等等。所以我开始看到那些可怕的只写(write-only)组件，这些组件使人们在并发编程挣扎着。我自己也身处其中。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 某天下午，我正坐在机场内，将要前往芝加哥为我的团队做一个关于并发的讲演。我正对讲演的PPT进行最后的处理，那组幻灯片着重演示了每一个重要的组件。为了引导我浏览java.util.concurrent中每个并发组件的状态，我写了一些状态机，它们展示了一些供我参考用的简单文本消息。在之前的生涯中，我曾在一家互联网创业公司中开发交互式的游戏，所以我懂得许多与动画相关的知识。这使我想到可以将PPT替换成一组交互式的动画应用，那会更为直观。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 在等飞机的过程中，我写了一个初步的动画引擎，然后在我的状态机中调用了这个引擎。到了第二天早晨，我已经有一个可用的原型程序。多年来，我一直致力于这个框架，并且吸引了其他专家的建议。我传递过一份早期版本给Brian Goetz，令人惊讶的是，他为每个动画程序都给出了建议。我将他的所有建议到吸收到了该框架中。在我的第一次JavaOne讲演中，Kirk Pepperdine加入了进来。他建议为动画应用在真正的PPT中加入描述，以便讲演者能记住正在讨论的内容。随后我加上那些描述，这确实非常有用--不只是对讲演者有用，对于终端用户也很有用。Heinz Kabutz也加入了那场讲演，并建议修改某些动画，以使它们更为直观。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 在另一场讲演中，一个很有激情的软件咨询师Oliver Zeigermann指出，很显然缺少了针对ConcurrentHashMap的动画。我问他是否有兴趣贡献这个动画，随后他添加了那个很有价值的动画程序。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：你能带着我们过一遍Java并发工具包中的类吗？并能否解释一下这些动画程序是如何使开发者们更易于深入理解这些类？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：好的，但在没有动画程序的情况下确实很难办到。让我们看看CyclicBarrier，它有两个重要的状态，如图2和图3所示，它们展示了一个障碍和四个成员。在图2中，我们可以看到有三个成员已经到了，所以它们被阻止继续前进。图3展示了，一旦第四个成员也到达了，每个成员又可以向前走了。</span><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/jiangshachina/JAC/JCA_02.PNG" height="569" width="873" /><br /><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/jiangshachina/JAC/JCA_03.PNG" height="570" width="872" /><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 这就形象地诠释了障碍的概念，亦即，在所有成员到达障碍点之前，每个成员必须等待。随着并发组件复杂度的增加--例如Fork/Join的动画，以及那些演示原生的wait和notify机制的动画--使用动画程序的好处就更不肖说了。</span><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：谈谈在创建这些动画程序的过程中所遇到的一些挑战。</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：有一些挑战。开始时，线程被表示成箭头。对于多数并发组件，这种表示法是有效的。后来我们必须提供一个可视化方案，不仅要表示线程，还要表示BlockingQueue中的对象。所以，我不得不引入一个称之为"精灵类型(sprite-type)"的概念，然后我们有了一个箭头型的精灵类型和一个新的"对象"型的精灵类型。后来，ConcurrentHashMap和AtomicInteger又需要新的精灵类型，因为我们试图要对他们的计算与交换行为进行可视化。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 后面又来了Fork/Join，新的挑战就是如何去表现那些完全不同于现有框架所表现的可视化部件。还有一个挑战，即Fork/Join动画需要解决一个实际的问题，但这个动画应该解决一个什么样的问题呢？</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 开始时，我让这个动画程序去求Fibonacci数列，但却行不通。我在这个问题上纠结了两天时间，直到我认识到Fibonacci数列(Fn+1=Fn+Fn-1)无法高效地并行化，因为每个值都依赖于它前面的值。所以，无论你如何试图对其实施并行化，它天生就是一个顺序化的计算。所以我换成了另一个问题--查找数组中的最大元素，这样就好了。在这个动画中，你可以很精确地看到如何使用一个随机的数列去解决这个问题(如图4所示)。</span><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/jiangshachina/JAC/JCA_04.PNG" /><br /><br /><span style="font-size: 10pt;"><strong>Java Magazine</strong>：你都在哪里讲演过这些动画程序？</span><br /><span style="font-size: 10pt;"><strong>Grazi</strong>：在JavaOne中讲演过几次，在其它的许多会议，如奥斯陆中的JavaZone，苏黎世的Jazoon，纽约的QCon，以及许多SIG(特别兴趣组)和JUG(Java用户组)中也都讲演过。我喜欢讲演，我也喜欢周游世界，而Java Concurrent Animated为我提供了一个极好的机会去做这两件事情。它总能获得极高的评价。</span><br /><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; Java Concurrent Animated的讲演提供了一种意识，并且它们也向出席的开发者们展示了下载这一框架的价值，而且它还展示了，如果你拥有了框架和灵感启迪，学习并发编程会是多么的容易。</span></div><img src ="http://www.blogjava.net/jiangshachina/aggbug/407310.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2013-12-07 17:45 <a href="http://www.blogjava.net/jiangshachina/archive/2013/12/07/407310.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java并发基础实践--分而治之(原)</title><link>http://www.blogjava.net/jiangshachina/archive/2013/10/23/405577.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Wed, 23 Oct 2013 15:27:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2013/10/23/405577.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/405577.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2013/10/23/405577.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/405577.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/405577.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java并发基础实践--分而治之本系列的第三篇文章将以实现一个极简单的查找最大数的任务为例，分别给出了四个版本：1.顺序执行；2.基于传统的Thread.join()；3.基于并发工具包的Future；4.基于JDK 7引入的Fork/Join框架。(2013.10.25最后更新)&nbsp;&nbsp;&nbsp; 分而治之(Divide-and-Conquer)是解决复杂问题的常用方法。在并发...&nbsp;&nbsp;<a href='http://www.blogjava.net/jiangshachina/archive/2013/10/23/405577.html'>阅读全文</a><img src ="http://www.blogjava.net/jiangshachina/aggbug/405577.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2013-10-23 23:27 <a href="http://www.blogjava.net/jiangshachina/archive/2013/10/23/405577.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java并发基础实践--退出任务II(原)</title><link>http://www.blogjava.net/jiangshachina/archive/2013/10/07/404690.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Mon, 07 Oct 2013 08:55:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2013/10/07/404690.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/404690.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2013/10/07/404690.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/404690.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/404690.html</trackback:ping><description><![CDATA[<div><div align="center"><strong><span style="font-size: 14pt;">Java并发基础实践--退出任务II</span></strong></div>在<a href="http://www.blogjava.net/jiangshachina/category/53896.html">本系列</a>的<a href="http://www.blogjava.net/jiangshachina/archive/2013/09/21/404269.html">上一篇</a>中所述的退出并发任务的方式都是基于JDK 5之前的API，本文将介绍使用由JDK 5引入的并发工具包中的API来退出任务。(2013.10.08最后更新)<br /><br />&nbsp;&nbsp;&nbsp; 在本系列的前一篇中讲述了三种退出并发任务的方式--停止线程；可取消的任务；中断，但都是基于JDK 5之前的API。本篇将介绍由JDK 5引入的java.concurrent包中的Future来取消任务的执行。<br /><br /><strong style="font-size: 12pt;">1. Future模式</strong><br style="font-size: 12pt;" />&nbsp;&nbsp;&nbsp; Future是并发编程中的一种常见设计模式，它相当于是Proxy模式与Thread-Per-Message模式的结合。即，每次都创建一个单独的线程去执行一个耗时的任务，并且创建一个Future对象去持有实际的任务对象，在将来需要的时候再去获取实际任务的执行结果。<br />依然先创建一个用于扫描文件的任务FileScannerTask，如代码清单1所示，<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单1</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScannerTask&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;File&nbsp;root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;ArrayList</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ArrayList</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;FileScannerTask(File&nbsp;root)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(root&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">root.exists()&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">root.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;IllegalArgumentException(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">root&nbsp;must&nbsp;be&nbsp;directory</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;root;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(root);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;filePath&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.getAbsolutePath();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filePaths.add(filePath);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(parent.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File[]&nbsp;children&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.listFiles();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(children&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(File&nbsp;child&nbsp;:&nbsp;children)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(child);<br />&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;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;getFilePaths()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;(List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">)&nbsp;filePaths.clone();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div>此处的文件扫描任务，提供了一个getFilePaths()方法以允许随时都可以取出当前已扫描过的文件的路径(相当于一个任务快照)。然后，创建一个针对该任务的Future类，如代码清单2所示，<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单2</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScannerFuture&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;FileScannerTask&nbsp;task&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;FileScannerFuture(FileScannerTask&nbsp;task)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(task).start();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.task&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;task;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;getResult()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;task.getFilePaths();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div>FileScannerFuture持有FileScannerTask的引用，并创建一个独立的线程来执行该任务。在任务的执行过程中，应用程序可以在"未来"的某个时刻去获取一个任务的快照，如代码清单3所示，<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单3</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FileScannerFuture&nbsp;future&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScannerFuture(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScannerTask(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)));<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths1&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;future.getResult();<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(filePaths1.size());<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths2&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;future.getResult();<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(filePaths2.size());<br />}</span></div><br /><strong style="font-size: 12pt;">2. 使用并发工具包中的Future实现</strong><br style="font-size: 12pt;" />&nbsp;&nbsp;&nbsp; 前面所展示的Future实现十分的简陋，没有实际应用的意义。使用FileScannerFuture，应用程序在获取filePaths时，无法得知其获取的是否为最终结果，即无法判断FileScannerTask是否已经完成。而且，也不能在必要时停止FileScannerTask的执行。毫无疑问，由JDK 5引入的并发工具包肯定会提供此类实用工具，如FutureTask。为了使用并发工具包中的Future，需要修改前述的FileScannerTask实现，让其实现Callable接口，如代码清单4所示，<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单4</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScannerTask&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Callable</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;File&nbsp;root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ArrayList</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;FileScannerTask(File&nbsp;root)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(root&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">root.exists()&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">root.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;IllegalArgumentException(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">root&nbsp;must&nbsp;be&nbsp;directory</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;root;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;call()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(root);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;filePaths;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;filePath&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.getAbsolutePath();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filePaths.add(filePath);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(parent.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File[]&nbsp;children&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.listFiles();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(children&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(File&nbsp;child&nbsp;:&nbsp;children)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(child);<br />&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;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;getFilePaths()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;(List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">)&nbsp;filePaths.clone();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div>应用程序也要相应的修改成如代码清单5所示，使用ExecutorService来提交任务，并创建一个Future/FutureTask实例。<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单5</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;executorService&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Executors.newCachedThreadPool();<br />&nbsp;&nbsp;&nbsp;&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">&nbsp;future&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;executorService.submit(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScannerTask(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)));<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;future.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(filePaths.size());<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(ExecutionException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;executorService.shutdown();<br />}</span></div>此处就是调用Future.get()方法来获取任务的执行结果，如果任务没有执行完毕，那么该方法将会被阻塞。该Future实现的好处就是，正常情况下，只有在任务执行完毕之后才能获取其结果，以保证该结果是最终执行结果。<br /><br /><strong><span style="font-size: 12pt;">3. 使用Future取消任务</span></strong><br />&nbsp;&nbsp;&nbsp; Future除了定义有可获取执行结果的get方法(get()以及get(long timeout, TimeUnit unit))，还定义了三个方法：cancel()，isCancelled()以及isDone()，用于取消任务，以及判定任务是否已被取消、已执行完毕。如代码清单6所示，<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单6</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">interface</span><span style="color: #000000; ">&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">V</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;cancel(</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;mayInterruptIfRunning);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;isCancelled();<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;isDone();<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />}</span></div>其中，cancel()方法中的boolean参数若为true，表示在取消该任务时，若执行该任务的线程仍在运行中，则对其进行中断。如代码清单7所示，若任务执行超时了，那么就取消它。<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单7</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;executorService&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Executors.newCachedThreadPool();<br />&nbsp;&nbsp;&nbsp;&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">&nbsp;future&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;executorService.submit(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScannerTask(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)));<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;future.get(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;TimeUnit.SECONDS);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(filePaths.size());<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(ExecutionException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(TimeoutException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">finally</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;future.cancel(</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;executorService.shutdown();<br />}</span></div>在实际应用中，取消任务的原由肯定不仅仅只是超时这么简单，还可能是由于接受到了用户的指令。此时，则可能会从另一个独立线程去取消该任务。除了取消任务之外，有时还需要取出任务中已经生成的部分结果。但为了能够响应任务的退出，首先需要修改FileScannerTask，使得当任务被取消(中断)时，任务能够真正的快速停止并返回，如代码清单8所示，<br /><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单8</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScannerTask&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Callable</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(Thread.currentThread().isInterrupted())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;filePath&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.getAbsolutePath();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filePaths.add(filePath);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(parent.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File[]&nbsp;children&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.listFiles();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(children&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(File&nbsp;child&nbsp;:&nbsp;children)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(child);<br />&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;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />}</span></div>相应地修改应用程序的代码，如代码清单9所示，</div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单9</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;executorService&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Executors.newCachedThreadPool();<br />&nbsp;&nbsp;&nbsp;&nbsp;FileScannerTask&nbsp;task&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScannerTask(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">));<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">&nbsp;future&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;executorService.submit(task);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Runnable()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<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;future.cancel(</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}).start();<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;future.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(filePaths.size());<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(ExecutionException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(CancellationException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;task.getFilePaths();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Partly&nbsp;result:&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;filePaths.size());<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;executorService.shutdown();<br />}</span></div>由上可知，此处使用Future.cancel(true)的本质依然是利用了线程的中断机制。<br /><br /><strong style="font-size: 12pt;">4. 小结</strong><br style="font-size: 12pt;" />&nbsp;&nbsp;&nbsp; 使用Future可以在任务启动之后的特定时机再去获取任务的执行结果。由JDK 5引入的并发工具包中提供的Future实现不仅可以获取任务的执行结果，还可以用于取消任务的执行。</div><img src ="http://www.blogjava.net/jiangshachina/aggbug/404690.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2013-10-07 16:55 <a href="http://www.blogjava.net/jiangshachina/archive/2013/10/07/404690.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java并发基础实践--退出任务I(原)</title><link>http://www.blogjava.net/jiangshachina/archive/2013/09/21/404269.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Sat, 21 Sep 2013 11:11:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2013/09/21/404269.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/404269.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2013/09/21/404269.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/404269.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/404269.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt;"> </span><div><div align="center"><strong><span style="font-size: 14pt;">Java并发基础实践--退出任务I</span></strong></div><span style="font-size: 10pt;">计划写一个"<a href="http://www.blogjava.net/jiangshachina/category/53896.html">Java并发基础实践</a>"系列，算作本人对Java并发学习与实践的简单总结。本文是该系列的第一篇，介绍了退出并发任务的最简单方法。(2013.09.25最后更新)</span><br /><br /><span style="font-size: 10pt;">在一个并发任务被启动之后，不要期望它总是会执行完成。由于时间限制，资源限制，用户操作，甚至是任务中的异常(尤其是运行时异常)，...都可能造成任务不能执行完成。如何恰当地退出任务是一个很常见的问题，而且实现方法也不一而足。</span><br /><br /><strong><span style="font-size: 12pt;">1. 任务</span></strong><br /><span style="font-size: 10pt;">创建一个并发任务，递归地获取指定目录下的所有子目录与文件的绝对路径，最后再将这些路径信息保存到一个文件中，如代码清单1所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单1</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScanner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;File&nbsp;root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ArrayList</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;FileScanner1(File&nbsp;root)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(root&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">root.exists()&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">root.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;IllegalArgumentException(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">root&nbsp;must&nbsp;be&nbsp;legal&nbsp;directory</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;root;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(root);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saveFilePaths();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(Exception&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;filePath&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.getAbsolutePath();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filePaths.add(filePath);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(parent.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File[]&nbsp;children&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.listFiles();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(File&nbsp;child&nbsp;:&nbsp;children)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(child);<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;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;saveFilePaths()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileWriter&nbsp;fos&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileWriter(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(root.getAbsoluteFile()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;File.separator&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">filePaths.out</span><span style="color: #000000; ">"</span><span style="color: #000000; ">));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(String&nbsp;filePath&nbsp;:&nbsp;filePaths)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fos.write(filePath&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fos.close();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><br /><strong><span style="font-size: 12pt;">2. 停止线程</span></strong><br /><span style="font-size: 10pt;">有一个很直接，也很干脆的方式来停止线程，就是调用Thread.stop()方法，如代码清单2所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单2</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FileScanner&nbsp;task&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScanner(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">));<br />&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;taskThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(task);<br />&nbsp;&nbsp;&nbsp;&nbsp;taskThread.start();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;taskThread.stop();<br />}</span></div><span style="font-size: 10pt;">但是，地球人都知道Thread.stop()在很久很久之前就不推荐使用了。根据<a href="http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html">官方文档</a>的介绍，该方法存在着固有的不安全性。当停止线程时，将会释放该线程所占有的全部监视锁，这就会造成受这些锁保护的对象的不一致性。在执行清单2的应用程序时，它的运行结果是不确定的。它可能会输出一个文件，其中包含部分的被扫描过的目录和文件。但它也很有可能什么也不输出，因为在执行FileWriter.write()的过程中，可能由于线程停止而造成了I/O异常，使得最终无法得到输出文件。</span><br /><br /><strong><span style="font-size: 12pt;">3. 可取消的任务</span></strong><br /><span style="font-size: 10pt;">另外一种十分常见的途径是，在设计之初，我们就使任务是可被取消的。一般地，就是提供一个取消标志或设定一个取消条件，一旦任务遇到该标志或满足了取消条件，就会结束任务的执行。如代码清单3所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单3</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScanner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;File&nbsp;root&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;List</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;filePaths&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ArrayList</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;cancel&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;FileScanner(File&nbsp;root)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(cancel)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;filePath&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.getAbsolutePath();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filePaths.add(filePath);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(parent.isDirectory())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File[]&nbsp;children&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;parent.listFiles();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(File&nbsp;child&nbsp;:&nbsp;children)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;travleFiles(child);<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;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;saveFilePaths()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;cancel()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cancel&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><span style="font-size: 10pt;">新的FileScanner实现提供一个cancel标志，travleFiles()会遍历新的文件之前检测该标志，若该标志为true，则会立即返回。代码清单4是使用新任务的应用程序。</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单4</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FileScanner&nbsp;task&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScanner(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">));<br />&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;taskThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(task);<br />&nbsp;&nbsp;&nbsp;&nbsp;taskThread.start();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">3</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;task.cancel();<br />}</span></div><span style="font-size: 10pt;">但有些时候使用可取消的任务，并不能快速地退出任务。因为任务在检测取消标志之前，可能正处于等待状态，甚至可能被阻塞着。对清单2中的FileScanner稍作修改，让每次访问新的文件之前先睡眠10秒钟，如代码清单5所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单5</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScanner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">10</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(cancel)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;saveFilePaths()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;cancel()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cancel&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><span style="font-size: 10pt;">再执行清单3中的应用程序时，可能发现任务并没有很快速的退出，而是又等待了大约7秒钟才退出。如果在检查cancel标志之前要先获取某个受锁保护的资源，那么该任务就会被阻塞，并且无法确定何时能够退出。对于这种情况，就需要使用中断了。</span><br /><br /><strong><span style="font-size: 12pt;">4. 中断</span></strong><br /><span style="font-size: 10pt;">中断是一种协作机制，它并不会真正地停止一个线程，而只是提醒线程需要被中断，并将线程的中断状态设置为true。如果线程正在执行一些可抛出InterruptedException的方法，如Thread.sleep()，Thread.join()和Object.wait()，那么当线程被中断时，上述方法就会抛出InterruptedException，并且中断状态会被重新设置为false。任务程序只要恰当处理该异常，就可以正常地退出任务。对清单5再稍作修改，即，如果任务在睡眠时遇上了InterruptedException，那么就取消任务。如代码清单6所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单6</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScanner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">10</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cancel();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(cancel)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />}</span></div><span style="font-size: 10pt;">同时将清单4中的应用程序，此时将调用Thread.interrupt()方法去中断线程，如代码清单7所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单7</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FileScanner3&nbsp;task&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileScanner3(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">C:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">));<br />&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;taskThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(task);<br />&nbsp;&nbsp;&nbsp;&nbsp;taskThread.start();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">3</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;taskThread.interrupt();<br />}</span></div><span style="font-size: 10pt;">或者更进一步，仅使用中断状态来控制程序的退出，而不再使用可取消的任务(即，删除cancel标志)，将清单6中的FileScanner修改成如下：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单8</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScanner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">10</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().interrupt();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(Thread.currentThread().isInterrupted())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />}</span></div><span style="font-size: 10pt;">再次执行清单7的应用程序后，新的FileScanner也能即时的退出了。值得注意的是，因为当sleep()方法抛出InterruptedException时，该线程的中断状态将又会被设置为false，所以必须要再次调用interrupt()方法来保存中断状态，这样在后面才可以利用中断状态来判定是否需要返回travleFiles()方法。当然，对于此处的例子，在收到InterruptedException时也可以选择直接返回，如代码清单9所示：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><em>清单9</em><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FileScanner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;travleFiles(File&nbsp;parent)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit.SECONDS.sleep(</span><span style="color: #000000; ">10</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />}</span></div><br /><strong><span style="font-size: 12pt;">5 小结</span></strong><br /><span style="font-size: 10pt;">本文介绍了三种简单的退出并发任务的方法：停止线程；使用可取消任务；使用中断。毫无疑问，停止线程是不可取的。使用可取消的任务时，要避免任务由于被阻塞而无法及时，甚至永远无法被取消。一般地，恰当地使用中断是取消任务的首选方式。</span></div><img src ="http://www.blogjava.net/jiangshachina/aggbug/404269.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2013-09-21 19:11 <a href="http://www.blogjava.net/jiangshachina/archive/2013/09/21/404269.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>你所不知道的五件事情--多线程编程(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2010/11/20/338571.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Sat, 20 Nov 2010 15:49:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2010/11/20/338571.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/338571.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2010/11/20/338571.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/338571.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/338571.html</trackback:ping><description><![CDATA[<div align="center"><span style="font-size: 10pt;"><strong><span style="font-size: 14pt;">你所不知道的五件事情--多线程编程</span></strong></span><br />
</div>
<span style="font-size: 10pt;">这是<a href="http://www.ibm.com/developerworks/">IBM developerWorks</a>中<a href="http://www.ibm.com/developerworks/java/library/j-5things15/index.html">5 things系列文章中的一篇</a>，讲述了关于多线程的一些应用窍门，值得大家学习。(2010.11.22最后更新)<br />
<br />
摘要：多线程编程不轻松，但它确实能帮助理解JVM如何细微地处理不同代码结构。Steven Haines将分享的5个窍门会帮助你在处理同步方法，volatile变量以及原子类时做出更为合理的决定。<br />
<br />
&nbsp;&nbsp;&nbsp; 尽管很少有Java开发者能够忽略多线程编程，且Java平台类库支持它，甚至于更少的开发者能有时间去深入学习线程。相反，我们只是泛泛地学习线程，如果需要的话，会向我们的工具箱中添加新的技巧和技术。通过这种方法你可能会构建且运行好的应用程序，但你还能做得更好。理解Java编译器和JVM的线程特性，可以帮助你编写更高效，性能更佳的Java代码。<br />
&nbsp;&nbsp;&nbsp; 在<a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=5+things+you+did">5 things系列</a>的本期文章中，我会介绍一些使用同步方法，volatile变量和原子类等多线程编程的细节方面。我的讨论特别关注在这些程序结构是如何与JVM和Java编译器进行交互的，以及不同的交互是如何影响Java应用程序性能的。<br />
<br />
<strong><span style="font-size: 12pt;">1. 同步方法与同步块</span></strong><br />
&nbsp;&nbsp;&nbsp; 你偶尔会衡量是否同步整个方法调用，或者只是同步方法中线程安全的子块。在这种情况下，知道Java编译器在何时将源代码转化为字节码是有帮助的，它在处理同步方法和同步块时是完全不同的。<br />
&nbsp;&nbsp;&nbsp; 当JVM在执行同步方法时，执行线程标识方法的method_info结构设有ACC_SYNCHRONIZED标记，然后它自动地获取对象的锁，调用方法，再释放锁。如果发生了异常，线程会自动释放锁。<br />
&nbsp;&nbsp;&nbsp; 另一方面，同步一个方法块，绕开JVM内建的对获取对象锁和异常处理的支持，这些功能要显式的写在字节码中。如果你读过含有同步块的方法的字节码，你将看到更多的额外操作去管理该功能。清单1展示了生成同步方法与同步块所产生的调用：<br />
<br />
<strong>清单1. 两种同步方法</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.geekcap;<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;SynchronizationExample&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;synchronizedMethodGet()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;synchronizedBlockGet()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">(&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">&nbsp;)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
synchronizedMethodGet()方法生成下列字节码：<br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;aload_0<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;getfield<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;nop<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;iconst_m1<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;ireturn</span></div>
<span style="font-size: 10pt;"><br />
而下面是synchronizedBlockGet()方法的字节码：<br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;aload_0<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;dup<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;astore_1<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;monitorenter<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;aload_0<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;getfield<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">6</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;nop<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">7</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;iconst_m1<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;aload_1<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">9</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;monitorexit<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;ireturn<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">11</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;astore_2<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;aload_1<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">13</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;monitorexit<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">14</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;aload_2<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">15</span><span style="color: #000000;">:&nbsp;&nbsp;&nbsp;&nbsp;athrow</span></div>
<span style="font-size: 10pt;"><br />
创建同步块会产生16行字节码，然而同步方法只返回5行代码。<br />
<br />
<strong><span style="font-size: 12pt;">2. ThreadLocal变量</span></strong><br />
&nbsp;&nbsp;&nbsp; 如果你想为一个类的所有实例维护单个变量实例，你将使用静态类成员变量来实现这一点。如果你想在每个线程中维护一个变量的实例，你将使用thread- local变量。ThreadLocal变量不同于平常的变量，在于每个线程有它自己的变量初始化实例，通过get()或set()方法可以访问这些变量。<br />
&nbsp;&nbsp;&nbsp; 让我们说，你正在开发多线程代码追踪器的目的是从你的程序去唯一地标识每个线程的路径。挑战在于你需要在跨越多个线程的多个类中协调多个方法。没有 ThreadLocal，这将是一个很复杂的问题。当一个线程开始执行时，它将生成一个唯一的标记以便于在追踪器中进行标识，并在在路径中将这个唯一标记传给每个方法。<br />
&nbsp;&nbsp;&nbsp; 使用ThreadLocal，问题就变得简单了。线程在运行的开始时初始化thread-local变量，然后在各个类的各个方法中去访问它，这就能确保该变量只会在当前执行线程中维护路径信息。当线程执行完毕时，线程会将它的特定路径传递给一个管理对象，该对象负责维护所有的路径。<br />
&nbsp;&nbsp;&nbsp; 当你需要基于每个线程来存储变量时，使用ThreadLocal就很有意义。<br />
<br />
<strong><span style="font-size: 12pt;">3. volatile变量</span></strong><br />
&nbsp;&nbsp;&nbsp; 我估计一大半Java开发员知道Java语言含有关键字volatile。其中大约只有10%的人知道它的意义，只有更少的人知道如何高效地使用它。简言之，将一个变量使用volatile关键字进行标识就意味着该变量的值将被不同的线程修改。为了充分理解volatile关键字的功用，首先就会帮助我们理解线程是如何处理非volatile变量的。<br />
&nbsp;&nbsp;&nbsp; 为了改进性能，Java语言规范允许JRE在各个线程中维护一份针对某个变量的引用的复本。你能够认为这些变量的"thread-local"复本类似于缓存，这会帮助线程避免在每次需要访问该变量的值时都去检查主内存。<br />
&nbsp;&nbsp;&nbsp; 但考虑下面场景可能会发生的事情：两个线程都启动了，第一个线程读到变量A的值为5，而第二个线程读到变量A的值为10。如果变量A已经从5变到10了，然后第一个线程并不会意识到这一变化，所以它会得到A的错误值。如果变量A被标记为volatile，然后在任何时候，某个线程读取A的值时，它都将查询 A的主复本并读到它的当前值。<br />
&nbsp;&nbsp;&nbsp; 如果应用中的变量不会改变，那么使用一个thread-local缓存将是有意义的。另外，知道volatile关键字能为你做些什么也是很有帮助的。<br />
<br />
<strong><span style="font-size: 12pt;">4. volatile对于同步</span></strong><br />
&nbsp;&nbsp;&nbsp; 如果变量被声明为volatile，就意味着它会被多个线程所修改。很自然地，你会希望JRE能为volatile变量以某种方式强制执行同步。幸运地是，当访问volatile变量时，JRE隐式地提供了同步，但会伴随一个很大的代价：读volatile变量是同步的，写volatile变量也是同步的，但非原子性操作不能怎么做。<br />
&nbsp;&nbsp;&nbsp; 这就意味着下面的代码不是线程安全的：<br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">myVolatileVar</span><span style="color: #000000;">++</span><span style="color: #000000;">;</span></div>
<span style="font-size: 10pt;"><br />
前面的语句可以写成如下形式：<br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;temp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br />
synchronize(&nbsp;myVolatileVar&nbsp;)&nbsp;{<br />
&nbsp;&nbsp;temp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;myVolatileVar;<br />
}<br />
<br />
temp</span><span style="color: #000000;">++</span><span style="color: #000000;">;<br />
<br />
synchronize(&nbsp;myVolatileVar&nbsp;)&nbsp;{<br />
&nbsp;&nbsp;myVolatileVar&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;temp;<br />
}</span></div>
<span style="font-size: 10pt;"><br />
&nbsp;&nbsp;&nbsp; 换言之，如果一个volatile变量按上述方法来进行更新，即先读取值，并修改之，然后再赋值，在两个同步操作之间，这个结果是非线程安全的。你可以考虑是使用同步，还是依赖JRE对volatile变量的自动同步。更好的方法是根据你的用例：如果赋给volatile变量的值依靠于它的当前值(例如加法操作)，如果你想操作是线程安全的，那就必须使用同步。<br />
<br />
<strong><span style="font-size: 12pt;">5. 原子字段更新器</span></strong><br />
&nbsp;&nbsp;&nbsp; 当在多线程环境中加或减一个原始数据类型时，使用java.util.concurrent包中新添加的原子类会比编写你自己的同步代码块要好得多。原子类保证能以线程安全的方式来执行这些操作，如加减数值，更新值，以及添加值。原子类包括 AtomicInteger，AtomicBoolean，AtomicLong，AtomicLong等等。<br />
&nbsp;&nbsp;&nbsp; 使用原子类的挑战在于所有的类方法，包括get，set，以及get-set方法簇都是原子化的。这就意味着read和write操作不会以同步的方式来修改原子变量的值，也不仅仅重要的读-更新-写操作。如果你想对同步代码的发布能有更好的控制，解决方法就是使用原子字段更新器。<br />
<br />
<strong>使用原子更新</strong><br />
&nbsp;&nbsp;&nbsp; 原子字段更新器，如AtomicIntegerFieldUpdater，AtomicLongFieldUpdater和 AtomicReferenceFieldUpdater，是用于volatile字段的基本包装器类。在JDK的内部，Java类库就在使用这些原子类。但在应用程序中，它们还未被广泛使用，你也没有理由不使用它们。<br />
&nbsp;&nbsp;&nbsp; 清单2展示的示例，是一个类使用原子更新来改变某人正在阅读的书：<br />
<br />
<strong>清单2. Book类</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.geeckap.atomicexample;<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Book<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;String&nbsp;name;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Book()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Book(&nbsp;String&nbsp;name&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.name&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;String&nbsp;getName()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setName(&nbsp;String&nbsp;name&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.name&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
Book类只是一个POJO(Plain Old Java Object)，只有一个字段：name。<br />
<br />
<strong>清单3. MyObject</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.geeckap.atomicexample;<br />
<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.atomic.AtomicReferenceFieldUpdater;<br />
<br />
</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;*<br />
&nbsp;*&nbsp;</span><span style="color: #808080;">@author</span><span style="color: #008000;">&nbsp;shaines<br />
&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;MyObject<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">volatile</span><span style="color: #000000;">&nbsp;Book&nbsp;whatImReading;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;AtomicReferenceFieldUpdater</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">MyObject,Book</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;updater&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AtomicReferenceFieldUpdater.newUpdater(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyObject.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;Book.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">whatImReading</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Book&nbsp;getWhatImReading()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;whatImReading;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setWhatImReading(&nbsp;Book&nbsp;whatImReading&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">this.whatImReading&nbsp;=&nbsp;whatImReading;</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;updater.compareAndSet(&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.whatImReading,&nbsp;whatImReading&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
&nbsp;&nbsp;&nbsp; 清单3中的MyObject类揭露了whatImReading属性就是你所期望的，该属性有get和set方法，但set方法做的一些事情不太一样。不同于简单地将内部的Book引用赋予一个特定的Book对象(使用清单3中被注释的代码就可以做到这一点)，该示例使用了一个 AtomicReferenceFieldUpdater。<br />
<br />
<strong>AtomicReferenceFieldUpdater</strong><br />
Javadoc对AtomicReferenceFieldUpdater有如下定义：<br />
&nbsp;&nbsp;&nbsp; 一个基于反射的工具类，它能对指定类的指定的volatile引用字段进行原子更新。该类被设计用于原子数据结构，在这种结构中，相同节点的多个引用字段会进行独立地原子更新。<br />
&nbsp;&nbsp;&nbsp; 在清单3中，通过调用AtomicReferenceFieldUpdater的静态方法newUpdater就能创建它的实例，该方法要接收三个参数：<br />
&nbsp;&nbsp;&nbsp; 包含该字段的对象的类(在这个例子中，就是MyObject)<br />
&nbsp;&nbsp;&nbsp; 将被自动更新的对象的类<br />
&nbsp;&nbsp;&nbsp; 将被自动更新的字段的名称<br />
<br />
在执行getWhatImReading方法获取实际值时没有使用任何形式的同步，然而setWhatImReading方法的执行则是一个原子操作。<br />
&nbsp;&nbsp;&nbsp; 清单4证明了如何去使用setWhatImReading()方法，以及如何判断变量的值进行了正确地修改：<br />
<br />
<strong>清单4. 练习原子更新的测试用例</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.geeckap.atomicexample;<br />
<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.junit.Assert;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.junit.Before;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.junit.Test;<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;AtomicExampleTest<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;MyObject&nbsp;obj;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;@Before<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setUp()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.setWhatImReading(&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Book(&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Java&nbsp;2&nbsp;From&nbsp;Scratch</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;)&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;@Test<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;testUpdate()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.setWhatImReading(&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Book(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Pro&nbsp;Java&nbsp;EE&nbsp;5&nbsp;Performance&nbsp;Management&nbsp;and&nbsp;Optimization</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;)&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.assertEquals(&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Incorrect&nbsp;book&nbsp;name</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Pro&nbsp;Java&nbsp;EE&nbsp;5&nbsp;Performance&nbsp;Management&nbsp;and&nbsp;Optimization</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.getWhatImReading().getName()&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
}</span></div>
<span style="font-size: 10pt;"><br />
查看资源以学习更多关于原子类的知识。<br />
<br />
<strong><span style="font-size: 12pt;">结论</span></strong><br />
&nbsp;&nbsp;&nbsp; 多线程编程总是存在着挑战性，但涉及到Java平台，它已经获得了支持去简化一些多线程编程任务。在本文中，我讨论了你在基于Java平台编写多线程应用时可能不知道的五件事情，包括同步方法与同步块的不同之处，使用ThreadLocal变量为每个线程去存储值，针对volatile关键字的广泛误解 (包括在需要同步时依赖volatile所产生的危险)，还简要地看了一下原子类的复杂之处。查看资源以学习到更多相关知识。<br />
<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/338571.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2010-11-20 23:49 <a href="http://www.blogjava.net/jiangshachina/archive/2010/11/20/338571.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>你所不知道的五件事情--java.util.concurrent(第二部分)(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2010/06/16/323650.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Wed, 16 Jun 2010 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2010/06/16/323650.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/323650.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2010/06/16/323650.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/323650.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/323650.html</trackback:ping><description><![CDATA[<div align="center"><span style="font-size: 10pt;"><strong><span style="font-size: 14pt;">你所不知道的五件事情--java.util.concurrent(第二部分)</span></strong></span><br />
</div>
<span style="font-size: 10pt;">这是<a href="http://www.tedneward.com/">Ted Neward</a>在<a href="http://www.ibm.com/developerworks/">IBM developerWorks</a>中<a href="http://www.ibm.com/developerworks/java/library/j-5things5.html">5 things系列文章中的一篇</a>，仍然讲述了关于Java并发集合API的一些应用窍门，值得大家学习。(2010.06.17最后更新)<br />
<br />
摘要：除了便于编写并发应用的集合API外，java.util.concurrent还引入了其它的预置程序组件，这些组件能辅助你在多线程应用中控制和执行线程。Ted Neward再介绍了五个来自于java.util.concurrent的Java编程必备窍门。<br />
<br />
&nbsp;&nbsp;&nbsp; 通过提供线程安全，性能良好的数据结构，并发集合框架使并发编程变得更容易。然而在有些情况下，开发者需要多走一步，并要考虑控制和/或调节线程的执行。提供java.util.concurrent包的全部原因就是为了简化多线程编程--事实上正是如此。<br />
&nbsp;&nbsp;&nbsp; 接着第一部分，本文介绍了多个同步数据结构，这些数据结构比核心语言基本结构(监视器)的层次要高，但不会高到将它们圈囿在一个集合类中。一旦知道了这些锁与栓的用途，就能径直去用了。<br />
<span style="font-size: 12pt;"><strong><br />
1. 信号量</strong></span><strong></strong><br />
&nbsp;&nbsp;&nbsp; 在有些企业级系统中，常需要开发者去控制针对特定资源的请求(线程或动作)的数量。虽然完全可能试着手工编写这样的调节程序，但使用Semaphore类会更容易些，该类会为你处理对线程的控制，如清单1所示：<br />
<br />
<strong>清单1. 使用信号量调节线程</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.</span><span style="color: #000000;">*</span><span style="color: #000000;">;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;SemApp<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Runnable&nbsp;limitedCall&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Runnable()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Random&nbsp;rand&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Random();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Semaphore&nbsp;available&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Semaphore(</span><span style="color: #000000;">3</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;count&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()<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;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;time&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;rand.nextInt(</span><span style="color: #000000;">15</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;num&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;count</span><span style="color: #000000;">++</span><span style="color: #000000;">;<br />
&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;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
&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;available.acquire();<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;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Executing&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><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;</span><span style="color: #000000;">"</span><span style="color: #000000;">long-running&nbsp;action&nbsp;for&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><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;time&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;seconds<img src="http://www.blogjava.net/Images/dot.gif" alt="" />&nbsp;#</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;num);<br />
&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;Thread.sleep(time&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Done&nbsp;with&nbsp;#</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><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;num&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;available.release();<br />
&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;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;intEx)<br />
&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;intEx.printStackTrace();<br />
&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;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">10</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(limitedCall).start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
&nbsp;&nbsp;&nbsp; 虽然上例有10个线程在运行(针对运行SemApp的Java进程执行jstack程序可以验证这一点)，但只有3个是活动的。另外7个线程会被保存起来，直到其中一个信号量计数器被释放出来。(准确地说，Semaphore类支持一次获取和释放一个以上的被许可线程，但在此处的场景中这么做没有意义。)<br />
<br />
<strong><span style="font-size: 12pt;">2. CountDownLatch</span></strong><br />
&nbsp;&nbsp;&nbsp; 如果并发类Semaphore是被设计为在同一时刻允许"其中"一个线程执行的话，那么CountDownLatch就是赛马比赛中的起跑门。该类持有所有的线程，当遇到某个特定条件，那时CountDownLatch就会一次性释放全部的线程。<br />
<strong><br />
清单2. CountDownLatch：让我们比赛！</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Race<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Random&nbsp;rand&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Random();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;distance&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;rand.nextInt(</span><span style="color: #000000;">250</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;CountDownLatch&nbsp;start;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;CountDownLatch&nbsp;finish;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;horses&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ArrayList</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Race(String<img src="http://www.blogjava.net/Images/dot.gif" alt="" />&nbsp;names)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.horses.addAll(Arrays.asList(names));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;InterruptedException<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">And&nbsp;the&nbsp;horses&nbsp;are&nbsp;stepping&nbsp;up&nbsp;to&nbsp;the&nbsp;gate<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;CountDownLatch&nbsp;start&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CountDownLatch(</span><span style="color: #000000;">1</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;CountDownLatch&nbsp;finish&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CountDownLatch(horses.size());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;places&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collections.synchronizedList(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ArrayList</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;String&nbsp;h&nbsp;:&nbsp;horses)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Runnable()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(h&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><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;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;stepping&nbsp;up&nbsp;to&nbsp;the&nbsp;gate<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000;">"</span><span style="color: #000000;">);<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;start.await();<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;<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;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;traveled&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<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;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(traveled&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;distance)<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;{<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;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;In&nbsp;a&nbsp;0-2&nbsp;second&nbsp;period&nbsp;of&nbsp;time<img src="http://www.blogjava.net/Images/dot.gif" alt="" />.</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&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;&nbsp;&nbsp;Thread.sleep(rand.nextInt(</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">);<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;&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;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />&nbsp;a&nbsp;horse&nbsp;travels&nbsp;0-14&nbsp;lengths</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&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;&nbsp;&nbsp;traveled&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;rand.nextInt(</span><span style="color: #000000;">15</span><span style="color: #000000;">);<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;&nbsp;&nbsp;System.out.println(h&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;advanced&nbsp;to&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;traveled&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<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;}<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;finish.countDown();<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;System.out.println(h&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><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;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;crossed&nbsp;the&nbsp;finish!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<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;places.add(h);<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;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;intEx)<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ABORTING&nbsp;RACE!!!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<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;intEx.printStackTrace();<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;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}).start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">And<img src="http://www.blogjava.net/Images/dot.gif" alt="" />&nbsp;they're&nbsp;off!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start.countDown();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finish.await();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">And&nbsp;we&nbsp;have&nbsp;our&nbsp;winners!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(places.get(</span><span style="color: #000000;">0</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;took&nbsp;the&nbsp;gold<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(places.get(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;got&nbsp;the&nbsp;silver<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">and&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;places.get(</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;took&nbsp;home&nbsp;the&nbsp;bronze.</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CDLApp<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;InterruptedException,&nbsp;java.io.IOException<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Prepping<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Race&nbsp;r&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Race(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Beverly&nbsp;Takes&nbsp;a&nbsp;Bath</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">RockerHorse</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Phineas</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Ferb</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Tin&nbsp;Cup</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">I'm&nbsp;Faster&nbsp;Than&nbsp;a&nbsp;Monkey</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Glue&nbsp;Factory&nbsp;Reject</span><span style="color: #000000;">"</span><span style="color: #000000;"><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;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">It's&nbsp;a&nbsp;race&nbsp;of&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;r.getDistance()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;lengths</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Press&nbsp;Enter&nbsp;to&nbsp;run&nbsp;the&nbsp;race<img src="http://www.blogjava.net/Images/dot.gif" alt="" />.</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.in.read();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.run();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
&nbsp;&nbsp;&nbsp; 注意在清单2中，CountDownLatch服务于两个目的：首先，它同时释放所有的线程，模拟比赛的开始；但之后，另一个CountDownLatch模拟了比赛的结束。一场比赛会有更多的评论，你可以在比赛的"转弯"和"半程"点添加CountDownLatch，当马匹跑过1/4程，半程和3/4程时。<br />
<br />
<strong><span style="font-size: 12pt;">3. Executor</span></strong><br />
&nbsp;&nbsp;&nbsp; 清单1和清单2中的例子都遭遇了一个令人非常沮丧的错误，你被迫要直接地创建Thread对象。这是一个造成麻烦的方式，因为在有些JVM中，创建Thread对象是一件重量级的工作，所以重用而非创建新的线程要好得多。然而在另一些JVM中，情况就恰恰相反：Thread是非常轻量级的，若你需要一个线程，直接创建它则会好得多。当然，如果Murphy有他自己的方法(他经常就是这么做的)，无论你使用哪种方法，对于你最终所依赖的某种Java平台都会是错误的。<br />
&nbsp;&nbsp;&nbsp; JSR-166专家组在一定程度上预见到了这种情况。与让Java开发者直接创建Thread实例不同，他们推荐Executor接口，这是一个创建新线程的抽象。如果清单3所示，Executor允许你自己不必使用new操作符去创建Thread对象：<br />
<br />
<strong>清单3. Executor</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">Executor&nbsp;exec&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;getAnExecutorFromSomeplace();<br />
exec.execute(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Runnable()&nbsp;{&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />&nbsp;});</span></div>
<span style="font-size: 10pt;"><br />
&nbsp;&nbsp;&nbsp; 使用Excutor的主要缺点与我们使用所有对象工厂所遇到的缺点一样：工厂必须来源于某处。不幸地是，不同于CLR，JVM并不带有一个标准的VM范围内的线程池。<br />
&nbsp;&nbsp;&nbsp; Executor类只是作为获取Executor实现实例的常用地方，但它只有new方法(例如，为了创建新的线程池)；它没有预创建的实例。所以，如果你想创建并使用一个能贯穿于整个程序的Executor实现，你就可以创建一个你自己的Executor实例。(或者，在有些情况下，你可以使用你所选容器/平台所提供的Executor实例。)<br />
<strong><br />
ExecutorService，为你服务</strong><br />
&nbsp;&nbsp;&nbsp; ExecutorService的用处在于使你不必关心Thread来自于何处，Executor接口缺乏Java开发者可能期望的一些功能，比如启动一个线程，该线程用于产生结果，它会以非阻塞方式一直等待，直到结果出现为止。(在桌面应用中这是很普通的需求，在这种应用中用户会执行一个需要访问数据库的UI操作，如果它耗时太长的话，就可能想要在它完成之前就取消这一操作。)<br />
&nbsp;&nbsp;&nbsp; 为此，JSR-166的专家们创造一个更为有用的抽象，ExecutorService接口，该接口将启动线程的工厂模型化为一个服务，这样就能对该服务进行集合化控制了。例如，不对每个任务调用一次execute()方法，ExecutorService能创建一个任务的集合，并可返回代表这些任务未来结果的Future集合。<br />
<br />
<strong><span style="font-size: 12pt;">4. ScheduledExecutorServices</span></strong><br />
&nbsp;&nbsp;&nbsp; 与ExecutorService接口同样优秀，特定的任务需要以计划的形式进行执行，例如在特定的时间间隔或在特定的时刻执行给定的任务。这就是继承自ExecutorService的ScheduledExecutorService的职责范畴。<br />
&nbsp;&nbsp;&nbsp; 如果你的目的是创建一个"心跳"命令，该命令每5秒钟就去"ping"一次。ScheduledExecutorService会帮你做到这一点，正如你在清单4中所见的那般简单：<br />
<strong><br />
清单4. ScheduledExecutorService按计划去"Ping"</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Ping<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScheduledExecutorService&nbsp;ses&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Executors.newScheduledThreadPool(</span><span style="color: #000000;">1</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Runnable&nbsp;pinger&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Runnable()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">PING!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<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;&nbsp;&nbsp;&nbsp;&nbsp;ses.scheduleAtFixedRate(pinger,&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">,&nbsp;TimeUnit.SECONDS);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
&nbsp;&nbsp;&nbsp; 怎么样？没有操作线程的烦恼，如果用户想取消心跳，也不必操心如何去做，前台或后台都没有显示的标记线程；所有的调度细节都留给了ScheduledExecutorService。<br />
&nbsp;&nbsp;&nbsp; 顺便提一下，如果用户想要取消心跳，从scheduleAtFixedRate()方法返回的会是一个ScheduledFuture实例，它不仅含有执行结果(如果有的话)，也有一个cancel()方法去停止该计划任务。<br />
<br />
<strong><span style="font-size: 12pt;">5. 超时方法</span></strong><br />
&nbsp;&nbsp;&nbsp; 拥有为阻塞操作置一个确定的超时控制的能力(这样就可以避免死锁)是java.util.concurrent类库相比于旧有并发API，如针对锁的监视器，的最大优点之一。<br />
&nbsp;&nbsp;&nbsp; 这些方法几乎总是按int/TimeUnit对的方式进行重载，该int/TimeUnit对用于指示方法在跳出执行并将控制返回给平台之前需要等待多长时间。这要求开发者对此做更多的工作--如果没有获得锁，将如何进行恢复？--但结果却几乎总是正确的：更少的死锁，以及更加生产安全的代码。(更多关于生产就绪的代码，请见Michael Nygard的Release It!)<br />
<br />
<strong><span style="font-size: 12pt;">结论</span></strong><br />
&nbsp;&nbsp;&nbsp; java.util.concurrent包含有许多更优雅的工具，它们出于集合框架，但更胜之，特别是.locks和.atomic包中的类。深入挖掘之，你将发现像CyclicBarrier这样的十分有用的控制结构，甚至于更多。<br />
&nbsp;&nbsp;&nbsp; 下一次，我们将步入一个新的主题：你所不知道的五件关于Jar的事情。<br />
<br />
<span style="font-size: 12pt;">请关注<a href="http://www.blogjava.net/jiangshachina/archive/2010/05/24/321683.html">你所不知道的五件事情--java.util.concurrent(第一部分)</a></span><a href="http://www.blogjava.net/jiangshachina/archive/2010/05/24/321683.html"></a><br />
<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/323650.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2010-06-16 11:42 <a href="http://www.blogjava.net/jiangshachina/archive/2010/06/16/323650.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>你所不知道的五件事情--java.util.concurrent(第一部分)(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2010/05/24/321683.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Mon, 24 May 2010 01:00:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2010/05/24/321683.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/321683.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2010/05/24/321683.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/321683.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/321683.html</trackback:ping><description><![CDATA[<div align="center"><span style="font-size: 10pt;"><strong><span style="font-size: 14pt;">你所不知道的五件事情--java.util.concurrent(第一部分)</span></strong></span><br />
<span style="font-size: 10pt;"><strong><span style="font-size: 12pt;">&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --使用并发集合类进行多线程编程</span></strong></span><br />
</div>
<span style="font-size: 10pt;">这是<a href="http://www.tedneward.com/">Ted Neward</a>在<a href="http://www.ibm.com/developerworks/">IBM developerWorks</a>中<a href="http://www.ibm.com/developerworks/java/library/j-5things4.html">5 things系列文章中的一篇</a>，讲述了关于Java并发集合API的一些应用窍门，值得大家学习。(2010.05.24最后更新)<br />
<br />
&nbsp;&nbsp;&nbsp; 摘要：编写既要性能良好又要防止应用崩溃的多线程代码确实很难--这也正是我们需要java.util.concurrent的原因。Ted Neward向你展示了像CopyOnWriteArrayList，BlockingQueue和ConcurrentMap这样的并发集合类是如何为了并发编程需要而改进标准集合类的。<br />
<br />
&nbsp;&nbsp;&nbsp; 并发集合API是Java 5的一大新特性，但由于对Annotation和泛型的热捧，许多Java开发者忽视了这些API。另外(可能更真实的是)，因为许多开发者猜想并发集合 API肯定很复杂，就像去尝试解决一些问题那样，所以开发者们会回避java.util.concurrent包。<br />
&nbsp;&nbsp;&nbsp; 事实上，java.util.concurrent的很多类并不需要你费很大力就能高效地解决通常的并发问题。继续看下去，你就能学到 java.util.concurrent中的类，如CopyOnWriteArrayList和BlockingQueue，是怎样帮助你解决多线程编程可怕的挑战。<br />
<br />
<strong><span style="font-size: 12pt;">1. TimeUnit</span></strong><br />
&nbsp;&nbsp;&nbsp; java.util.concurrent.TimeUnit本身并不是集合框架类，这个枚举使得代码非常易读。使用TimeUnit能够将开发者从与毫秒相关的困苦中解脱出来，转而他们自己的方法或API。<br />
&nbsp;&nbsp;&nbsp; TimeUnit能与所有的时间单元协作，范围从毫秒和微秒到天和小时，这就意味着它能处理开发者可能用到的几乎所有时间类型。还要感谢这个枚举类型声明的时间转换方法，当时间加快时，它甚至能细致到把小时转换回毫秒。<br />
<br />
<strong><span style="font-size: 12pt;">2. CopyOnWriteArrayList</span></strong><br />
&nbsp;&nbsp;&nbsp; 制作数组的干净复本是一项成本极高的操作，在时间和内存这两方面均有开销，以至于在通常的应用中不能考虑该方法；开发者常常求助于使用同步的 ArrayList来替代前述方法。但这也是一个比较有代价的选项，因为当每次你遍历访问该集合中的内容时，你不得不同步所有的方法，包括读和写，以确保内存一致性。<br />
&nbsp;&nbsp;&nbsp; 在有大量用户在读取ArrayList而只有很少用户对其进行修改的这一场景中，上述方法将使成本结构变得缓慢。<br />
&nbsp;&nbsp;&nbsp; CopyOnWriteArrayList就是解决这一问题的一个极好的宝贝工具。它的Javadoc描述到，ArrayList通过创建数组的干净复本来实现可变操作(添加，修改，等等)，而CopyOnWriteArrayList则是ArrayList的一个"线程安全"的变体。<br />
&nbsp;&nbsp;&nbsp; 对于任何修改操作，该集合类会在内部将其内容复制到一个新数组中，所以当读用户访问数组的内容时不会招致任何同步开销(因为它们没有对可变数据进行操作)。<br />
&nbsp;&nbsp;&nbsp; 本质上，创建CopyOnWriteArrayList的想法，是出于应对当ArrayList无法满足我们要求时的场景：经常读，而很少写的集合对象，例如针对JavaBean事件的Listener。<br />
<br />
<strong><span style="font-size: 12pt;">3. BlockingQueue</span></strong><br />
&nbsp;&nbsp;&nbsp; BlockingQueue接口表明它是一个Queue，这就意味着它的元素是按先进先出(FIFO)的次序进行存储的。以特定次序插入的元素会以相同的次序被取出--但根据插入保证，任何从空队列中取出元素的尝试都会堵塞调用线程直到该元素可被取出时为止。同样地，任何向一个已满队列中插入元素的尝试将会堵塞调用线程直到该队列的存储空间有空余时为止。<br />
&nbsp;&nbsp;&nbsp; 在不需要显式地关注同步问题时，如何将由一个线程聚集的元素"交给"另一个线程进行处理呢，BlockingQueue很灵巧地解决了这个问题。Java Tutorial中Guarded Blocks一节是很好的例子。它使用手工同步和wait()/notifyAll()方法创建了一个单点(single-slot)受限缓冲，当一个新的元素可被消费且当该点已经准备好被一个新的元素填充时，该方法就会在线程之间发出信号。(详情请见<a href="http://java.sun.com/docs/books/tutorial/essential/concurrency/guardmeth.html">Guarded Blocks</a>)<br />
&nbsp;&nbsp;&nbsp; 尽管教程Guarded Blocks中的代码可以正常工作，但它比较长，有些凌乱，而且完全不直观。诚然，在Java平台的早期时代，Java开发者们不得不；但现在已经是 2010年了--问题已经得到改进？<br />
&nbsp;&nbsp;&nbsp; 清单1展示的程序重写了Guarded Blocks中的代码，其中我使用ArrayBlockingQueue替代了手工编写的Drop。<br />
<strong><br />
清单1. BlockingQueue</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Producer<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Runnable<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;drop;<br />
&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;messages&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Arrays.asList(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Mares&nbsp;eat&nbsp;oats</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Does&nbsp;eat&nbsp;oats</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Little&nbsp;lambs&nbsp;eat&nbsp;ivy</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Wouldn't&nbsp;you&nbsp;eat&nbsp;ivy&nbsp;too?</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Producer(BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;d)&nbsp;{&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.drop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(String&nbsp;s&nbsp;:&nbsp;messages)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop.put(s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop.put(</span><span style="color: #000000;">"</span><span style="color: #000000;">DONE</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;intEx)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Interrupted!&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Last&nbsp;one&nbsp;out,&nbsp;turn&nbsp;out&nbsp;the&nbsp;lights!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Consumer<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Runnable<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;drop;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Consumer(BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;d)&nbsp;{&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.drop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;msg&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">((msg&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;drop.take()).equals(</span><span style="color: #000000;">"</span><span style="color: #000000;">DONE</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(msg);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;intEx)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Interrupted!&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Last&nbsp;one&nbsp;out,&nbsp;turn&nbsp;out&nbsp;the&nbsp;lights!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ABQApp<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;drop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ArrayBlockingQueue(</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Producer(drop))).start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Consumer(drop))).start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<br />
<span style="font-size: 10pt;">
ArrayBlockingQueue也崇尚"公平"--即意味着，它能给予读和写线程先进先出的访问次序。该方法可能是一种更高效的策略，但它也加大了造成线程饥饿的风险。(就是说，当其它读线程持有锁时，该策略可更高效地允许读线程进行执行，但这也就会产生读线程的常量流使写线程总是无法执行的风险)<br />
&nbsp;&nbsp;&nbsp; BlockingQueue也支持在方法中使用时间参数，当插入或取出元素出了问题时，方法需要返回以发出操作失败的信号，而该时间参数指定了在返回前应该阻塞多长时间。<br />
<br />
<strong><span style="font-size: 12pt;">4. ConcurrentMap</span></strong><br />
&nbsp;&nbsp;&nbsp; Map有一些细微的并发Bug，会使许多粗心的Java开发者误入歧途。ConcurrentMap则是一个简单的决定方案。<br />
&nbsp;&nbsp;&nbsp; 当有多个线程在访问一个Map时，通常在储存一个键/值对之前通常会使用方法containsKey()或get()去确定给出的键是否存在。即使用同步的Map，某个线程仍可在处理的过程中潜入其中，然后获得对Map的控制权。问题在于，在get()方法的开始处获得了锁，然后在调用方法put()去重新获得该锁之前会先释放它。这就导致了竞争条件：两个线程之间的竞争，根据哪个线程先执行，其结果将不尽相同。<br />
&nbsp;&nbsp;&nbsp; 如果两个线程在同一时刻调用一个方法，一个测试键是否存在，另一个则置入新的键/值对，那么在此过程中，第一个线程的值将会丢失。幸运地是，ConcurrentMap接口支持一组额外的方法，设计这些方法是为了在一个锁中做两件事情：例如，putIfAbsent()首先进行测试，之后只有当该键还未存储到Map中时，才执行置入操作。<br />
<br />
<strong><span style="font-size: 12pt;">5. SynchronousQueues</span></strong><br />
&nbsp;&nbsp;&nbsp; 根据Javadoc的描述，SynchronousQueue是一个很有趣的创造物：<br />
&nbsp;&nbsp;&nbsp; 一个阻塞队列在每次的插入操作中必须等等另一线程执行对应的删除线程，反之亦然。同步队列并没有任何内部的存储空间，一个都没有。<br />
&nbsp;&nbsp;&nbsp; 本质上，SynchronousQueue是之前提及的BlockingQueue的另一种实现。使用ArrayBlockingQueue利用的阻塞语义，SynchronousQueue给予我们一种极轻量级的途径在两个线程之间交换单个元素。在清单2中，我用SynchronousQueue替代 ArrayBlockingQueue重写了清单1的代码：<br />
<br />
<strong>清单2 SynchronousQueue</strong><br />
</span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Producer<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Runnable<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;drop;<br />
&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;messages&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Arrays.asList(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Mares&nbsp;eat&nbsp;oats</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Does&nbsp;eat&nbsp;oats</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Little&nbsp;lambs&nbsp;eat&nbsp;ivy</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Wouldn't&nbsp;you&nbsp;eat&nbsp;ivy&nbsp;too?</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Producer(BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;d)&nbsp;{&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.drop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(String&nbsp;s&nbsp;:&nbsp;messages)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop.put(s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop.put(</span><span style="color: #000000;">"</span><span style="color: #000000;">DONE</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;intEx)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Interrupted!&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Last&nbsp;one&nbsp;out,&nbsp;turn&nbsp;out&nbsp;the&nbsp;lights!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Consumer<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Runnable<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;drop;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Consumer(BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;d)&nbsp;{&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.drop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;msg&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">((msg&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;drop.take()).equals(</span><span style="color: #000000;">"</span><span style="color: #000000;">DONE</span><span style="color: #000000;">"</span><span style="color: #000000;">)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(msg);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;intEx)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Interrupted!&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Last&nbsp;one&nbsp;out,&nbsp;turn&nbsp;out&nbsp;the&nbsp;lights!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;SynQApp<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;drop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SynchronousQueue</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Producer(drop))).start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Thread(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Consumer(drop))).start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;"><br />
上述实现看起来几乎相同，但该应用程序已新加了一个好处，在这个实现中，只有当有线程正在等待消费某个元素时，SynchronousQueue才会允许将该元素插入到队列中。<br />
就实践方式来看，SynchronousQueue类似于Ada或CSP等语言中的"交会通道(Rendezvous Channel)"。在其它环境中，有时候被称为"连接"。<br />
<br />
<strong><span style="font-size: 12pt;">结论</span></strong><br />
&nbsp;&nbsp;&nbsp; 当Java运行时类库预先已经提供了方便使用的等价物时，为什么还要费力地向集合框架中引入并发呢？本系列的下一篇文章将探索 java.util.concurrent命名空间的更多内容。<br />
<br />
<span style="font-size: 12pt;">请关注<a href="http://www.blogjava.net/jiangshachina/archive/2010/06/16/323650.html">你所不知道的五件事情--java.util.concurrent(第二部分)</a></span><a href="http://www.blogjava.net/jiangshachina/archive/2010/06/16/323650.html"></a><br />
<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/321683.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2010-05-24 09:00 <a href="http://www.blogjava.net/jiangshachina/archive/2010/05/24/321683.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Callable返回结果(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2008/05/31/204007.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Sat, 31 May 2008 14:24:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2008/05/31/204007.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/204007.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2008/05/31/204007.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/204007.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/204007.html</trackback:ping><description><![CDATA[<div align="center"><strong><span style="font-size: 10pt;"><span style="font-size: 14pt;">使用Callable返回结果</span></span></strong><br />
</div>
<span style="font-size: 10pt;">
&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt;">本文是Sun官方以Blog形式发布的Java核心技术窍门(<a href="http://blogs.sun.com/CoreJavaTechTips/">JavaCoreTechTip</a>)中的一个。本文主要介绍了Callable及其相关接口和类的使用，篇幅不长且易于理解，故翻译在了此处，相信对于准备或刚接触java.util.concurrent的朋友会有所帮助。(2008.05.31最后更新)<br />
<br />
</span><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 自从Java平台的最开始，Runnable接口就已存在了。它允许你定义一个可由线程完成的任务。如大多数人所已知的那样，它只提供了一个run方法，该方法既不接受任何参数，也不返回任何值。如果你需要从一个未完成的任务中返回一个值，你就必须在该接口之外使用一个方法去等待该任务完成时通报的某种消息。例如，下面的示例就是你在这种情景下可能做的事情：<br />
&nbsp;&nbsp;&nbsp; Runnable runnable = ...;<br />
&nbsp;&nbsp;&nbsp; Thread t = new Thread(runnable);<br />
&nbsp;&nbsp;&nbsp; t.start();<br />
&nbsp;&nbsp;&nbsp; t.join();<br />
&nbsp;&nbsp;&nbsp; String value = someMethodtoGetSavedValue()<br />
严格来说，上述代码并无错误，但现在可用不同的方法去做，这要感谢J2SE 5.0引入的Callable接口。不同于Runnable接口拥有run方法，Callable接口提供的是call方法，该方法可以返回一个Object对象，或可返回任何一个在泛型化格式中定义了的特定类型的对象。<br />
&nbsp;&nbsp;&nbsp; public interface Callable&lt;V&gt; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V call() throws Exception;<br />
&nbsp;&nbsp;&nbsp; }<br />
因为你不可能把Callable对象传到Thread对象去执行，你可换用ExecutorService对象去执行Callable对象。该服务接受Callable对象，并经由submit方法去执行它。<br />
&nbsp;&nbsp;&nbsp; &lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task)<br />
如该方法的定义所示，提交一个Callable对象给ExecutorService会返回一个Future对象。然后，Future的get方法将会阻塞，直到任务完成。<br />
&nbsp;&nbsp;&nbsp; 为了证明这一点，下面的例子为命令行中的每个词都创建一个单独的Callable实例，然后把这些词的长度加起来。各个Callable对象将只是计算它自己的词的长度之和。Futures对象的Set集合将被保存以便从中获得计算用的值。如果需要保持返回值的顺序，则可换用一个List对象。</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.util.</span><span style="color: #000000; ">*</span><span style="color: #000000; ">;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.util.concurrent.</span><span style="color: #000000; ">*</span><span style="color: #000000; ">;<br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;CallableExample&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;WordLengthCallable<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Callable&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;String&nbsp;word;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;WordLengthCallable(String&nbsp;word)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.word&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;word;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;Integer&nbsp;call()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;Integer.valueOf(word.length());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String&nbsp;args[])&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;pool&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Executors.newFixedThreadPool(</span><span style="color: #000000; ">3</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Integer</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">&nbsp;set&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;HashSet</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Future</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">lg;Integer</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(String&nbsp;word:&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Callable</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Integer</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;callable&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;WordLengthCallable(word);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Integer</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;future&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;pool.submit(callable);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set.add(future);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;sum&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Integer</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;future&nbsp;:&nbsp;set)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum&nbsp;</span><span style="color: #000000; ">+=</span><span style="color: #000000; ">&nbsp;future.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">The&nbsp;sum&nbsp;of&nbsp;lengths&nbsp;is&nbsp;%s%n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;sum);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(sum);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><span style="font-size: 10pt;">
WordLengthCallable保存了每个词并使用该词的长度作为call方法的返回值。这个值可能会花点儿时间去生成，不过在这个例子中，可以立即知道它。 call方法的唯一要求是这个值要在call方法的结尾处返回。当Future的get方法稍后被调用时，如果任务运行得很快的话，Future将会自动得到这个值(如同本例的情况)，否则将一直等到该值生成完毕为止。多次调用get方法不会导致任务从该线程返回。因为该程序的目的是计划所有字的长度之和，它不会强令Callable任务结束。如果最后一个任务在前三个任务之前完成，也是没错的。对Future的get方法的第一次调用将只会等待Set中第一个任务结束，而不会阻塞其它的任务分别执行完毕。它只会等待当次线程或任务结束。这个特定的例子使用固定数线程池来产生ExecutorService对象，但其它有效的方法也是可行的。<br />
&nbsp;&nbsp;&nbsp; 关于执行器和线程池用法的更多信息，请见Java Tutorial中<a href="http://java.sun.com/tutorial/essential/concurrency/executors.html">Executors</a>一节。SwingWorker类是另一个使用Future的Runnable对象的例子，尽管有些微不同之处。更多信息请见Java Tutorial中<a href="http://java.sun.com/docs/books/tutorial/uiswing/concurrency/worker.html">Worker Threads and SwingWorker</a>一节。<br />
<br />
</span><img src ="http://www.blogjava.net/jiangshachina/aggbug/204007.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2008-05-31 22:24 <a href="http://www.blogjava.net/jiangshachina/archive/2008/05/31/204007.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Tutorials -- Concurrency(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2007/10/28/156522.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Sun, 28 Oct 2007 11:51:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2007/10/28/156522.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/156522.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2007/10/28/156522.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/156522.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/156522.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java Tutorials -- Concurrency&nbsp;&nbsp;&nbsp; 近一段时间在使用Thinking in Java(4th, English)和Java Concurrency in Practice学习Java并发编程。不得不说官方的Java Tutorias是很好的Java并发编程入门级教程，故将它其中的Concurrency一章翻译在了此处。与我翻译Ja...&nbsp;&nbsp;<a href='http://www.blogjava.net/jiangshachina/archive/2007/10/28/156522.html'>阅读全文</a><img src ="http://www.blogjava.net/jiangshachina/aggbug/156522.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2007-10-28 19:51 <a href="http://www.blogjava.net/jiangshachina/archive/2007/10/28/156522.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>