﻿<?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-随笔分类-Java并发基础实践</title><link>http://www.blogjava.net/jiangshachina/category/53896.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 12:46:37 GMT</lastBuildDate><pubDate>Tue, 22 Apr 2014 12:46:37 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并发基础实践--分而治之(原)</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></channel></rss>