﻿<?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-xylz,imxylz-随笔分类-Java Concurrency</title><link>http://www.blogjava.net/xylz/category/45607.html</link><description>关注后端架构、中间件、分布式和并发编程</description><language>zh-cn</language><lastBuildDate>Fri, 29 Nov 2013 12:38:07 GMT</lastBuildDate><pubDate>Fri, 29 Nov 2013 12:38:07 GMT</pubDate><ttl>60</ttl><item><title>随机选择集合的子元素集合</title><link>http://www.blogjava.net/xylz/archive/2013/08/17/402978.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Sat, 17 Aug 2013 09:44:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2013/08/17/402978.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/402978.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2013/08/17/402978.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/402978.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/402978.html</trackback:ping><description><![CDATA[<div>我需要一个从集合N中随机选择M个子元素的算法。 当然最好的办法是将集合打乱顺序，然后从中选择前M个元素即可。 Java中现成的API可以使用：</div>
<div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #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 />
-->java.util.Collections.shuffle(List&lt;?&gt;)<br />
</div>
</div>
<div>
<div>此算法非常简单，循环N次，每次长度减少1，随机获取其中一个元素，然后交换其对称元素。</div>
</div>
<div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #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: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;shuffle(List&lt;?&gt;&nbsp;list,&nbsp;Random&nbsp;rnd)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;size&nbsp;=&nbsp;list.size();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(size&nbsp;&lt;&nbsp;SHUFFLE_THRESHOLD&nbsp;||&nbsp;list&nbsp;<span style="color: #0000FF; ">instanceof</span>&nbsp;RandomAccess)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(<span style="color: #0000FF; ">int</span>&nbsp;i=size;&nbsp;i&gt;1;&nbsp;i--)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;swap(list,&nbsp;i-1,&nbsp;rnd.nextInt(i));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;arr[]&nbsp;=&nbsp;list.toArray();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Shuffle&nbsp;array</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(<span style="color: #0000FF; ">int</span>&nbsp;i=size;&nbsp;i&gt;1;&nbsp;i--)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;swap(arr,&nbsp;i-1,&nbsp;rnd.nextInt(i));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Dump&nbsp;array&nbsp;back&nbsp;into&nbsp;list</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListIterator&nbsp;it&nbsp;=&nbsp;list.listIterator();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(<span style="color: #0000FF; ">int</span>&nbsp;i=0;&nbsp;i&lt;arr.length;&nbsp;i++)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it.set(arr[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
</div>
<div><br />
</div>
<div>
<div>有点意思的swap函数</div>
</div>
<div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #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 />
--><br />
<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;swap(List&lt;?&gt;&nbsp;list,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;j)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;List&nbsp;l&nbsp;=&nbsp;list;<br />
&nbsp;&nbsp;&nbsp;&nbsp;l.set(i,&nbsp;l.set(j,&nbsp;l.get(i)));<br />
}<br />
</div>
</div>
<div><br />
</div>
<div>
<div>其实我们的需求很简单，在基本不变的集合中，多次重复随机获取其子集，至于子集是否有序或者随机不重要的， 重要的是原集合中的每个元素都有相似的概率出现在子集合中。</div>
<div><br />
</div>
<div>考虑到性能以及并发访问（多线程）的需要，我想到了一个简单的算法：</div>
</div>
<div>给定N个元素集合，从中选择M(0&lt;M&lt;=N)个元素的办法是，</div>
<div>
<ol>
     <li>随机选择索引K(0&lt;=K&lt;N), i=0, 空子集</li>
     <li>取有效元素N(k-i),N(k+i) 加入未满子集M</li>
     <li>i+=1, 重复(2) 直到子集M已满</li>
     <li>终止</li>
</ol>
</div>
<div>
<div>这样取出来的元素虽然和原始集顺序有一定的关系，但是每个元素在子集里出现的概率相当，满足结果要求。 最后生成的算法如下：</div>
</div>
<div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #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: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;&lt;T&gt;&nbsp;List&lt;T&gt;&nbsp;randomList(List&lt;T&gt;&nbsp;views,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;max)&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;size&nbsp;=&nbsp;views.size();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;index&nbsp;=&nbsp;RandomUtils.nextInt(size);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;T&gt;&nbsp;ret&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;ArrayList&lt;T&gt;(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;low&nbsp;=&nbsp;index&nbsp;-&nbsp;1,&nbsp;high&nbsp;=&nbsp;index;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(max&nbsp;&gt;&nbsp;0&nbsp;&amp;&amp;&nbsp;(low&nbsp;&gt;=&nbsp;0&nbsp;||&nbsp;high&nbsp;&lt;&nbsp;size))&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(low&nbsp;&gt;=&nbsp;0&nbsp;&amp;&amp;&nbsp;max--&nbsp;&gt;&nbsp;0)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(views.get(low));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(high&nbsp;&lt;&nbsp;size&nbsp;&amp;&amp;&nbsp;max--&nbsp;&gt;&nbsp;0)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(views.get(high));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;low--;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;high++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;ret;<br />
}</div>
</div>
<div><br />
</div>
<div>此算法满足如下特点：</div>
<div>
<ol>
     <li>足够快</li>
     <li>线程安全（原始集合不变）</li>
     <li>子元素出现概率相当（未经数学证明</li>
</ol>
<div><br />
</div>
</div>
<div>另外，stackoverflow上也有一些参考链接：</div>
<div>
<ul>
     <li><a href="http://stackoverflow.com/questions/48087/select-a-random-n-elements-from-listt-in-c-sharp" target="_blank">
     </a></li>
     <li><a href="http://stackoverflow.com/questions/48087/select-a-random-n-elements-from-listt-in-c-sharp" target="_blank">Select a random N elements from List in C#</a></li>
     <a href="http://stackoverflow.com/questions/48087/select-a-random-n-elements-from-listt-in-c-sharp" target="_blank">
     </a>
     <li>http://mcherm.com/permalinks/1/a-random-selection-algorithm</li>
     <li>http://stackoverflow.com/questions/4702036/take-n-random-elements-from-a-liste</li>
</ul>
</div>
<br />
<div>[ 原文地址&nbsp;<a href="http://imxylz.com/blog/2013/08/14/select-a-random-sublist-from-list-in-java/">http://imxylz.com/blog/2013/08/14/select-a-random-sublist-from-list-in-java/</a>&nbsp;]</div><img src ="http://www.blogjava.net/xylz/aggbug/402978.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2013-08-17 17:44 <a href="http://www.blogjava.net/xylz/archive/2013/08/17/402978.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>捕获Java线程池执行任务抛出的异常</title><link>http://www.blogjava.net/xylz/archive/2013/08/05/402405.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Mon, 05 Aug 2013 08:45:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2013/08/05/402405.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/402405.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2013/08/05/402405.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/402405.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/402405.html</trackback:ping><description><![CDATA[<p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常，</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">interface</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">abstract</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run();<br />}</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">那么如果 run() 方法中抛出了RuntimeException，将会怎么处理了？</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">通常java.lang.Thread对象运行设置一个默认的异常处理方法：</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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; ">java.lang.Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)<br /></span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">而这个默认的静态全局的异常捕获方法时输出堆栈。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">当然，我们可以覆盖此默认实现，只需要一个自定义的java.lang.Thread.UncaughtExceptionHandler接口实现即可。</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">interface</span><span style="color: #000000; ">&nbsp;UncaughtExceptionHandler&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;uncaughtException(Thread&nbsp;t,&nbsp;Throwable&nbsp;e);<br />}</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">而在线程池中却比较特殊。默认情况下，线程池 java.util.concurrent.ThreadPoolExecutor 会Catch住所有异常， 当任务执行完成(java.util.concurrent.ExecutorService.submit(Callable<t>))获取其结果 时(java.util.concurrent.Future.get())会抛出此RuntimeException。</t></p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;*&nbsp;Waits&nbsp;if&nbsp;necessary&nbsp;for&nbsp;the&nbsp;computation&nbsp;to&nbsp;complete,&nbsp;and&nbsp;then<br />&nbsp;*&nbsp;retrieves&nbsp;its&nbsp;result.<br />&nbsp;*<br />&nbsp;*&nbsp;</span><span style="color: #808080; ">@return</span><span style="color: #008000; ">&nbsp;the&nbsp;computed&nbsp;result<br />&nbsp;*&nbsp;</span><span style="color: #808080; ">@throws</span><span style="color: #008000; ">&nbsp;CancellationException&nbsp;if&nbsp;the&nbsp;computation&nbsp;was&nbsp;cancelled<br />&nbsp;*&nbsp;</span><span style="color: #808080; ">@throws</span><span style="color: #008000; ">&nbsp;ExecutionException&nbsp;if&nbsp;the&nbsp;computation&nbsp;threw&nbsp;an&nbsp;exception<br />&nbsp;*&nbsp;</span><span style="color: #808080; ">@throws</span><span style="color: #008000; ">&nbsp;InterruptedException&nbsp;if&nbsp;the&nbsp;current&nbsp;thread&nbsp;was&nbsp;interrupted&nbsp;while&nbsp;waiting<br />&nbsp;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />V&nbsp;get()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException,&nbsp;ExecutionException;</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">其中 ExecutionException 异常即是java.lang.Runnable 或者 java.util.concurrent.Callable 抛出的异常。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">也就是说，线程池在执行任务时捕获了所有异常，并将此异常加入结果中。这样一来线程池中的所有线程都将无法捕获到抛出的异常。 从而无法通过设置线程的默认捕获方法拦截的错误异常。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">也不同通过<a href="http://stackoverflow.com/questions/1838923/why-is-uncaughtexceptionhandler-not-called-by-executorservice" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: #751590; -webkit-transition: color 0.3s; transition: color 0.3s; white-space: pre-wrap; word-wrap: break-word;">自定义线程</a>来完成异常的拦截。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">好在java.util.concurrent.ThreadPoolExecutor 预留了一个方法，运行在任务执行完毕进行扩展（当然也预留一个protected方法beforeExecute(Thread t, Runnable r)）：</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">protected void afterExecute(Runnable r, Throwable t) { } </code></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">此方法的默认实现为空，这样我们就可以通过继承或者覆盖ThreadPoolExecutor 来达到自定义的错误处理。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">解决办法如下：</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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; ">ThreadPoolExecutor&nbsp;threadPoolExecutor&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ThreadPoolExecutor(</span><span style="color: #000000; ">11</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">100</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;TimeUnit.MINUTES,&nbsp;</span><span style="color: #008000; ">//<br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ArrayBlockingQueue</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Runnable</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">(</span><span style="color: #000000; ">10000</span><span style="color: #000000; ">),</span><span style="color: #008000; ">//<br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;DefaultThreadFactory())&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">protected</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;afterExecute(Runnable&nbsp;r,&nbsp;Throwable&nbsp;t)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">super</span><span style="color: #000000; ">.afterExecute(r,&nbsp;t);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printException(r,&nbsp;t);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />};<br /><br /></span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;printException(Runnable&nbsp;r,&nbsp;Throwable&nbsp;t)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(t&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; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;r&nbsp;</span><span style="color: #0000FF; ">instanceof</span><span style="color: #000000; ">&nbsp;Future</span><span style="color: #000000; ">&lt;?&gt;</span><span style="color: #000000; ">)&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;Future</span><span style="color: #000000; ">&lt;?&gt;</span><span style="color: #000000; ">&nbsp;future&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(Future</span><span style="color: #000000; ">&lt;?&gt;</span><span style="color: #000000; ">)&nbsp;r;<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;(future.isDone())<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;future.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(CancellationException&nbsp;ce)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;ce;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(ExecutionException&nbsp;ee)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;ee.getCause();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;ie)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().interrupt();&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;ignore/reset</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(t&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error(t.getMessage(),&nbsp;t);<br />}</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">此办法的关键在于，事实上 afterExecute 并不会总是抛出异常 Throwable t，通过查看源码得知，异常是封装在此时的Future对象中的， 而此Future对象其实是一个java.util.concurrent.FutureTask<v>的实现，默认的run方法其实调用的 java.util.concurrent.FutureTask.Sync.innerRun()。</v></p><code style="margin: 0px; padding: 0px; border: 0px; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"> </code><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">void</span>&nbsp;innerRun()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(!compareAndSetState(0,&nbsp;RUNNING))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;runner&nbsp;=&nbsp;Thread.currentThread();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(getState()&nbsp;==&nbsp;RUNNING)&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;recheck&nbsp;after&nbsp;setting&nbsp;thread</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;innerSet(callable.call());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseShared(0);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;cancel</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">catch</span>&nbsp;(Throwable&nbsp;ex)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;innerSetException(ex);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><br /><span style="color: #0000FF; ">void</span>&nbsp;innerSetException(Throwable&nbsp;t)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;s&nbsp;=&nbsp;getState();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(s&nbsp;==&nbsp;RAN)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(s&nbsp;==&nbsp;CANCELLED)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;aggressively&nbsp;release&nbsp;to&nbsp;set&nbsp;runner&nbsp;to&nbsp;null,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;in&nbsp;case&nbsp;we&nbsp;are&nbsp;racing&nbsp;with&nbsp;a&nbsp;cancel&nbsp;request<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;that&nbsp;will&nbsp;try&nbsp;to&nbsp;interrupt&nbsp;runner</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseShared(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(compareAndSetState(s,&nbsp;RAN))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception&nbsp;=&nbsp;t;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseShared(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;done();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">这里我们可以看到它吃掉了异常，将异常存储在java.util.concurrent.FutureTask.Sync的exception字段中：</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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: #008000; ">/**</span><span style="color: #008000; ">&nbsp;The&nbsp;exception&nbsp;to&nbsp;throw&nbsp;from&nbsp;get()&nbsp;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;Throwable&nbsp;exception;<br /></span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">当我们获取异步执行的结果时， java.util.concurrent.FutureTask.get()</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;V&nbsp;get()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException,&nbsp;ExecutionException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;sync.innerGet();<br />}</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">java.util.concurrent.FutureTask.Sync.innerGet()</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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; ">V&nbsp;innerGet()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException,&nbsp;ExecutionException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;acquireSharedInterruptibly(</span><span style="color: #000000; ">0</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(getState()&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;CANCELLED)<br />&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;CancellationException();<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(exception&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ExecutionException(exception);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;result;<br />}</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">异常就会被包装成ExecutionException异常抛出。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">也就是说当我们想线程池 ThreadPoolExecutor(java.util.concurrent.ExecutorService)提交任务时， 如果不理会任务结果（Feture.get()），那么此异常将被线程池吃掉。</p><pre style="margin-top: 0px; margin-bottom: 2.1em; padding: 0.8em 1em; border: 1px solid #05232b; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.45em; font-size: 13px; vertical-align: baseline; -webkit-box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; box-shadow: rgba(0, 0, 0, 0.0588235) 0px 0px 10px; background-image: url(http://imxylz.com/images/noise.png?1375426420); background-color: #002b36; border-top-left-radius: 0.4em; border-top-right-radius: 0.4em; border-bottom-right-radius: 0.4em; border-bottom-left-radius: 0.4em; color: #93a1a1; overflow: auto; background-position: 0% 0%;"><div style="background-color: #eeeeee; 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; ">&lt;</span><span style="color: #000000; ">T</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">T</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;submit(Callable</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">T</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;task);<br />Future</span><span style="color: #000000; ">&lt;?&gt;</span><span style="color: #000000; ">&nbsp;submit(Runnable&nbsp;task);</span></div></pre><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">而java.util.concurrent.ScheduledThreadPoolExecutor是继承ThreadPoolExecutor的，因此情况类似。</p><p style="margin: 0px 0px 1.5em; padding: 0px; border: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 27.59375px; font-size: 18px; vertical-align: baseline; color: #222222; background-color: #f8f8f8;">结论，通过覆盖ThreadPoolExecutor.afterExecute 方法，我们才能捕获到任务的异常（RuntimeException）。<br /><br />原文地址：<span style="font-family: verdana, 'courier new'; font-size: 14px; line-height: 21px;"><a href="http://imxylz.com/blog/2013/08/02/handling-the-uncaught-exception-of-java-thread-pool/" target="_blank">http://imxylz.com/blog/2013/08/02/handling-the-uncaught-exception-of-java-thread-pool/</a></span></p><img src ="http://www.blogjava.net/xylz/aggbug/402405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2013-08-05 16:45 <a href="http://www.blogjava.net/xylz/archive/2013/08/05/402405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (40): 并发总结 part 4 性能与伸缩性</title><link>http://www.blogjava.net/xylz/archive/2011/12/31/367641.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Sat, 31 Dec 2011 06:13:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/12/31/367641.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/367641.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/12/31/367641.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/367641.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/367641.html</trackback:ping><description><![CDATA[<h1>性能与伸缩性</h1>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">使用线程的一种说法是为了提高性能。多线程可以使程序充分利用闲置的资源，提高资源的利用率，同时能够并行处理任务，提高系统的响应性。 但是很显然，引入线程的同时也引入了系统的复杂性。另外系统的性能并不是总是随着线程数的增加而总是提高。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>性能与伸缩性</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">性能的提升通常意味着可以用更少的资源做更多的事情。这里资源是包括我们常说的CPU周期、内存、网络带宽、磁盘IO、数据库、WEB服务等等。 引入多线程可以充分利用多核的优势，充分利用IO阻塞带来的延迟，也可以降低网络开销带来的影响，从而提高单位时间内的响应效率。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">为了提高性能，需要有效的利用我们现有的处理资源，同时也要开拓新的可用资源。例如，对于CPU而言，理想状况下希望CPU能够满负荷工作。当然这里满负荷工作是指做有用的事情，而不是无谓的死循环或者等待。受限于CPU的计算能力，如果CPU达到了极限，那么很显然我们充分利用了计算能力。对于IO而言（内存、磁盘、网络等），如果达到了其对于的带宽，这些资源的利用率也就上去了。理想状况下所有资源的能力都被用完了，那么这个系统的性能达到了最大值。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">为了衡量系统的性能，有一些指标用于定性、定量的分析。例如服务时间、等待时间、吞吐量、效率、可伸缩性、生成量等等。服务时间、等待时间等用于衡量系统的效率，即到底有多快。吞吐量、生成量等用于衡量系统的容量，即能够处理多少数据。除此之外，有效服务时间、中断时间等用于能力系统的可靠性和稳定性等。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">可伸缩性的意思是指增加计算资源，吞吐量和生产量相应得到的改进。 从算法的角度讲，通常用复杂度来衡量其对应的性能。例如时间复杂度、空间复杂度等。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>Amdahl定律</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">并行的任务增加资源显然能够提高性能，但是如果是串行的任务，增加资源并不一定能够得到合理的性能提升。&nbsp;<a href="http://en.wikipedia.org/wiki/Amdahl%27s_law" rel="nofollow" style="text-decoration: none; ">Amdahl定律</a>描述的在一个系统中，增加处理器资源对系统行的提升比率。 假定在一个系统中，F是必须串行化执行的比重，N是处理器资源，那么随着N的增加最多增加的加速比：</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><img src="http://www.blogjava.net/images/blogjava_net/xylz/amdahl.png" width="200" height="71" alt="" /></div>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">理论上，当N趋近于无穷大时，加速比最大值无限趋近于1/F。 这意味着如果一个程序的串行化比重为50%，那么并行化后最大加速比为2倍。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">加速比除了可以用于加速的比率外，也可以用于衡量CPU资源的利用率。如果每一个CPU的资源利用率为100%，那么CPU的资源每次翻倍时，加速比也应该翻倍。 事实上，在拥有10个处理器的系统中，程序如果有10%是串行化的，那么最多可以加速1/(0.1+(1-0.1)/10)=5.3倍，换句话说CPU的利用率只用5.3/10=53%。而如果处理器增加到100倍，那么加速比为9.2倍，也就是说CPU的利用率只有个9.3%。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">显然增加CPU的数量并不能提高CPU的利用率。下图描述的是随着CPU的数量增加，不同串行化比重的系统的加速比。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<div style="font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><img src="http://www.blogjava.net/images/blogjava_net/xylz/utilization.png" width="495" height="306" alt="" /></div>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">很显然，串行比重越大，增加CPU资源的效果越不明显。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>性能提升</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">性能的提升可以从以下几个方面入手。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>系统平台的资源利用率</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">一个程序对系统平台的资源利用率是指某一个设备繁忙且服务于此程序的时间占所有时间的比率。从物理学的角度讲类似于有用功的比率。简单的说就是：资源利用率=有效繁忙时间/总耗费时间。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">也就说尽可能的让设备做有用的功，同时榨取其最大值。无用的循环可能会导致CPU 100%的使用率，但不一定是有效的工作。有效性通常难以衡量，通常只能以主观来评估，或者通过被优化的程序的行为来判断是否提高了有效性。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>延迟</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">延迟描述的是完成任务所耗费的时间。延迟有时候也成为响应时间。如果有多个并行的操作，那么延迟取决于耗费时间最大的任务。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>多处理</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">多处理是指在单一系统上同时执行多个进程或者多个程序的能力。多处理能力的好处是可以提高吞吐量。多处理可以有效利用多核CPU的资源。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>多线程</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">多线程描述的是同一个地址空间内同时执行多个线程的过程。这些线程都有不同的执行路径和不同的栈结构。我们说的并发性更多的是指针对线程。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>并发性</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">同时执行多个程序或者任务称之为并发。单程序内的多任务处理或者多程序间的多任务处理都认为是并发。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>吞吐量</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">吞吐量衡量系统在单位之间内可以完成的工作总量。对于硬件系统而言，吞吐量是物理介质的上限。在没有达到物理介质之前，提高系统的吞吐量也可以大幅度改进性能。同时吞吐量也是衡量性能的一个指标。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>瓶颈</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">程序运行过程中性能最差的地方。通常而言，串行的IO、磁盘IO、内存单元分配、网络IO等都可能造成瓶颈。某些使用太频繁的算法也有可能成为瓶颈。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>可扩展性</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">这里的可扩展性主要是指程序或系统通过增加可使用的资源而增加性能的能力。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>线程开销</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">假设引入的多线程都用于计算，那么性能一定会有很大的提升么？ 其实引入多线程以后也会引入更多的开销。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>切换上下文</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">如果可运行的线程数大于CPU的内核数，那么OS会根据一定的调度算法，强行切换正在运行的线程，从而使其它线程能够使用CPU周期。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">切换线程会导致上下文切换。线程的调度会导致CPU需要在操作系统和进程间花费更多的时间片段，这样真正执行应用程序的时间就减少了。另外上下文切换也会导致缓存的频繁进出，对于一个刚被切换的线程来说，可能由于高速缓冲中没有数据而变得更慢，从而导致更多的IO开销。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>内存同步</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">不同线程间要进行数据同步，synchronized以及volatile提供的可见性都会导致缓存失效。线程栈之间的数据要和主存进行同步，这些同步有一些小小的开销。如果线程间同时要进行数据同步，那么这些同步的线程可能都会受阻。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h3>阻塞</h3>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">当发生锁竞争时，失败的线程会导致阻塞。通常阻塞的线程可能在JVM内部进行自旋等待，或者被操作系统挂起。自旋等待可能会导致更多的CPU切片浪费，而操作系统挂起则会导致更多的上下文切换。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">了解了性能的提升的几个方面，也了解性能的开销后，应用程序就要根据实际的场景进行取舍和评估。没有一劳永逸的优化方案，不断的进行小范围改进和调整是提高性能的有效手段。当前一些大的架构调整也会导致较大的性能的提升。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">简单的原则是在保证逻辑正确的情况小，找到性能瓶颈，小步改进和优化。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>参考资料</h2>
<ul style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">
     <li>Amdahl's law:&nbsp;<a href="http://en.wikipedia.org/wiki/Amdahl%27s_law" rel="nofollow" style="text-decoration: none; ">http://en.wikipedia.org/wiki/Amdahl%27s_law</a></li>
     <li>Gustafson's law:&nbsp;<a href="http://en.wikipedia.org/wiki/Gustafson%27s_law" rel="nofollow" style="text-decoration: none; ">http://en.wikipedia.org/wiki/Gustafson%27s_law</a></li>
     <li>Sun-Ni law:&nbsp;<a href="http://en.wikipedia.org/wiki/Sun-Ni_law" rel="nofollow" style="text-decoration: none; ">http://en.wikipedia.org/wiki/Sun-Ni_law</a></li>
     <li>多核系统中三种典型锁竞争的加速比分析&nbsp;<a href="http://blog.csdn.net/drzhouweiming/article/details/1800319" rel="nofollow" style="text-decoration: none; ">http://blog.csdn.net/drzhouweiming/article/details/1800319</a></li>
     <li>阿姆达尔定律和Gustafson定律的等价性&nbsp;<a href="http://book.51cto.com/art/201004/197506.htm" rel="nofollow" style="text-decoration: none; ">http://book.51cto.com/art/201004/197506.htm</a></li>
</ul>
<p>&nbsp;</p>
<div id="index">
<div id="previous"><a href="http://www.blogjava.net/xylz/archive/2011/12/30/367592.html">并发总结 part 3 常见的并发陷阱</a> </div>
<div id="center" align="center"><a href="http://www.blogjava.net/xylz/archive/2010/07/08/325587.html"><strong>目&nbsp;&nbsp; 录</strong></a> </div>
<div id="next"><a name="over">暂时完结</a></div>
</div><img src ="http://www.blogjava.net/xylz/aggbug/367641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-12-31 14:13 <a href="http://www.blogjava.net/xylz/archive/2011/12/31/367641.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (39): 并发总结 part 3 常见的并发陷阱</title><link>http://www.blogjava.net/xylz/archive/2011/12/30/367592.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Fri, 30 Dec 2011 09:25:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/12/30/367592.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/367592.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/12/30/367592.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/367592.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/367592.html</trackback:ping><description><![CDATA[<h1>常见的并发陷阱</h1>
<h2>volatile</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">volatile只能强调数据的可见性，并不能保证原子操作和线程安全，因此volatile不是万能的。参考<a href="http://www.blogjava.net/xylz/archive/2010/07/03/325168.html" rel="nofollow" style="text-decoration: none; ">指令重排序</a></p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">volatile最常见于下面两种场景。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">a. 循环检测机制<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">volatile</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;done&nbsp;=&nbsp;<span style="color: #0000FF; ">false</span>;<br />
<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(&nbsp;!&nbsp;done&nbsp;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dosomething();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><br />
b. 单例模型 （<a href="http://www.blogjava.net/xylz/archive/2009/12/18/306622.html%ef%bc%89" rel="nofollow" style="text-decoration: none; ">http://www.blogjava.net/xylz/archive/2009/12/18/306622.html）<br />
<br />
</a></p>
<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 />
--><a href="http://www.blogjava.net/xylz/archive/2009/12/18/306622.html%ef%bc%89" rel="nofollow" style="text-decoration: none; "><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;DoubleLockSingleton&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;DoubleLockSingleton&nbsp;instance&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;DoubleLockSingleton()&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;DoubleLockSingleton&nbsp;getInstance()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(instance&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;</span><span style="color: #0000FF; ">synchronized</span><span style="color: #000000; ">&nbsp;(DoubleLockSingleton.</span><span style="color: #0000FF; ">class</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; ">if</span><span style="color: #000000; ">&nbsp;(instance&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;&nbsp;&nbsp;&nbsp;&nbsp;instance&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;DoubleLockSingleton();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;instance;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></a></div>
<p>&nbsp;</p>
<h2><br />
synchronized/Lock</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">看起来Lock有更好的性能以及更灵活的控制，是否完全可以替换synchronized？</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">在<a href="http://www.blogjava.net/xylz/archive/2010/07/16/326246.html" rel="nofollow" style="text-decoration: none; ">锁的一些其它问题</a>中说过，synchronized的性能随着JDK版本的升级会越来越高，而Lock优化的空间受限于CPU的性能，很有限。另外JDK内部的工具（线程转储）对synchronized是有一些支持的（方便发现死锁等），而对Lock是没有任何支持的。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">也就说简单的逻辑使用synchronized完全没有问题，随着机器的性能的提高，这点开销是可以忽略的。而且从代码结构上讲是更简单的。简单就是美。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">对于复杂的逻辑，如果涉及到读写锁、条件变量、更高的吞吐量以及更灵活、动态的用法，那么就可以考虑使用Lock。当然这里尤其需要注意Lock的正确用法。<br />
</p>
<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 />
-->Lock&nbsp;lock&nbsp;=&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
lock.lock();<br />
<span style="color: #0000FF; ">try</span>{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">do&nbsp;something</span><span style="color: #008000; "><br />
</span>}<span style="color: #0000FF; ">finally</span>{<br />
&nbsp;&nbsp;&nbsp;&nbsp;lock.unlock();<br />
}</div>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><br />
一定要将Lock的释放放入finally块中，否则一旦发生异常或者逻辑跳转，很有可能会导致锁没有释放，从而发生死锁。而且这种死锁是难以排查的。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">如果需要synchronized无法做到的尝试锁机制，或者说担心发生死锁无法自恢复，那么使用tryLock()是一个比较明智的选择的。<br />
</p>
<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 />
-->Lock&nbsp;lock&nbsp;=&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
<span style="color: #0000FF; ">if</span>(lock.tryLock()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">do&nbsp;something</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">finally</span>{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock.unlock();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p>&nbsp;</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">甚至可以使用获取锁一段时间内超时的机制Lock.tryLock(long,TimeUnit)。 锁的使用可以参考前面文章的描述和建议。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>锁的边界</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">一个流行的错误是这样的。<br />
</p>
<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 />
-->ConcurrentMap&lt;String,String&gt;&nbsp;map&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;ConcurrentHashMap&lt;String,String&gt;();<br />
<br />
<span style="color: #0000FF; ">if</span>(!map.containsKey(key)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;map.put(key,value);<br />
}</div>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><br />
看起来很合理的，对于一个线程安全的Map实现，要存取一个不重复的结果，先检测是否存在然后加入。 其实我们知道两个原子操作和在一起的指令序列不代表就是线程安全的。 割裂的多个原子操作放在一起在多线程的情况下就有可能发生错误。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">实际上ConcurrentMap提供了putIfAbsent(K, V)的&#8220;原子操作&#8221;机制，这等价于下面的逻辑：<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">if</span>(map.containsKey(key)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;map.get(key);<br />
}<span style="color: #0000FF; ">else</span>{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;map.put(k,v);<br />
}</div>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><br />
除了putIfAbsent还有replace(K, V)以及replace(K, V, V)两种机制来完成组合的操作。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">提到Map，这里有一篇谈<a href="http://www.blogjava.net/xylz/archive/2009/12/18/306602.html" rel="nofollow" style="text-decoration: none; ">HashMap读写并发</a>的问题。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>构造函数启动线程</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">下面的实例是在构造函数中启动一个线程。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Runner{<br />
&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;x,y;<br />
&nbsp;&nbsp;&nbsp;Thread&nbsp;thread;<br />
&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;Runner(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.x=1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.y=2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.thread=<span style="color: #0000FF; ">new</span>&nbsp;MyThread();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.thread.start();<br />
&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><br />
这里可能存在的陷阱是如果此类被继承，那么启动的线程可能无法正确读取子类的初始化操作。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">因此一个简单的原则是，禁止在构造函数中启动线程，可以考虑但是提供一个方法来启动线程。如果非要这么做，最好将类设置为final，禁止继承。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>丢失通知的问题</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><a href="http://www.blogjava.net/xylz/archive/2011/09/05/326988.html" rel="nofollow" style="text-decoration: none; ">这篇文章</a>里面提到过notify丢失通知的问题。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">对于wait/notify/notifyAll以及await/singal/singalAll，如果不确定到底是否能够正确的收到消息，担心丢失通知，简单一点就是总是通知所有。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">如果担心只收到一次消息，使用循环一直监听是不错的选择。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">非常主用性能的系统，可能就需要区分到底是通知单个还是通知所有的挂起者。</p>
<div style="margin-top: 1.33em; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "></div>
<h2>线程数</h2>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">并不是线程数越多越好，在下一篇文章里面会具体了解下性能和可伸缩性。 简单的说，线程数多少没有一个固定的结论，受限于CPU的内核数，IO的性能以及依赖的服务等等。因此选择一个合适的线程数有助于提高吞吐量。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">对于CPU密集型应用，线程数和CPU的内核数一致有助于提高吞吐量，所有CPU都很繁忙，效率就很高。 对于IO密集型应用，线程数受限于IO的性能，某些时候单线程可能比多线程效率更高。但通常情况下适当提高线程数，有利于提高网络IO的效率，因为我们总是认为网络IO的效率比较低。</p>
<p style="margin-top: 1.33em; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; ">对于线程池而言，选择合适的线程数以及任务队列是提高线程池效率的手段。<br />
</p>
<div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;ThreadPoolExecutor(<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;corePoolSize,<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;maximumPoolSize,<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;keepAliveTime,<br />
&nbsp;&nbsp;&nbsp;&nbsp;TimeUnit&nbsp;unit,<br />
&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue&lt;Runnable&gt;&nbsp;workQueue,<br />
&nbsp;&nbsp;&nbsp;&nbsp;ThreadFactory&nbsp;threadFactory,<br />
&nbsp;&nbsp;&nbsp;&nbsp;RejectedExecutionHandler&nbsp;handler)</div>
<p>&nbsp;</p>
<p style="margin-top: 0px; margin-bottom: 0px; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 19px; background-color: #ffffff; "><br />
对于线程池来说，如果任务总是有积压，那么可以适当提高corePoolSize大小；如果机器负载较低，那么可以适当提高maximumPoolSize的大小；任务队列不长的情况下减小keepAliveTime的时间有助于降低负载；另外任务队列的长度以及任务队列的<a href="http://www.blogjava.net/xylz/archive/2011/01/18/343183.html" rel="nofollow" style="text-decoration: none; ">拒绝策略</a>也会对任务的处理有一些影响。</p>
<p>&nbsp;</p>
<div id="index">
<div id="previous"><a href="http://www.blogjava.net/xylz/archive/2011/12/29/367480.html">并发总结 part 2 常见的并发场景</a> </div>
<div id="center" align="center"><a href="http://www.blogjava.net/xylz/archive/2010/07/08/325587.html"><strong>目&nbsp;&nbsp; 录</strong></a> </div>
<div id="next"><a href="http://www.blogjava.net/xylz/archive/2011/12/31/367641.html">并发总结 part 4 性能与伸缩性</a> </div>
</div><img src ="http://www.blogjava.net/xylz/aggbug/367592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-12-30 17:25 <a href="http://www.blogjava.net/xylz/archive/2011/12/30/367592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (38): 并发总结 part 2 常见的并发场景</title><link>http://www.blogjava.net/xylz/archive/2011/12/29/367480.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Thu, 29 Dec 2011 08:31:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/12/29/367480.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/367480.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/12/29/367480.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/367480.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/367480.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 线程池<br><br>并发最常见用于线程池，显然使用线程池可以有效的提高吞吐量。<br>最常见、比较复杂一个场景是Web容器的线程池。Web容器使用线程池同步或者异步处理HTTP请求，同时这也可以有效的复用HTTP连接，降低资源申请的开销。通常我们认为HTTP请求时非常昂贵的，并且也是比较耗费资源和性能的，所以线程池在这里就扮演了非常重要的角色。<br>在线程池的章节中非常详细的讨论了线程池的原理和使用，同时也提到了，线程池的配置和参数对性能的影响是巨大的。不尽如此，受限于资源（机器的性能、网络的带宽等等）、依赖的服务，客户端的响应速度等，线程池的威力也不会一直增长。达到了线程池的瓶颈后，性能和吞吐量都会大幅度降低。<br>一直增加机器的性能或者增大线程的个数，并不一定能有效的提高吞吐量。高并发的情况下，机器的负载会大幅提升，这时候机器的稳定性、服务的可靠性都会下降。<br>尽管如此，线程池依然是提高吞吐量的一个有效措施，配合合适的参数能够有效的充分利用资源，提高资源的利用率。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/12/29/367480.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/367480.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-12-29 16:31 <a href="http://www.blogjava.net/xylz/archive/2011/12/29/367480.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (37): 并发总结 part 1 死锁与活跃度</title><link>http://www.blogjava.net/xylz/archive/2011/12/29/365149.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Thu, 29 Dec 2011 06:04:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/12/29/365149.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/365149.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/12/29/365149.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/365149.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/365149.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 死锁与活跃度<br><br>前面谈了很多并发的特性和工具，但是大部分都是和锁有关的。我们使用锁来保证线程安全，但是这也会引起一些问题。<br>锁顺序死锁(lock-ordering deadlock)：多个线程试图通过不同的顺序获得多个相同的资源，则发生的循环锁依赖现象。<br>动态的锁顺序死锁（Dynamic Lock Order Deadlocks）：多个线程通过传递不同的锁造成的锁顺序死锁问题。<br>资源死锁（Resource Deadlocks）：线程间相互等待对方持有的锁，并且谁都不会释放自己持有的锁发生的死锁。也就是说当现场持有和等待的目标成为资源，就有可能发生此死锁。这和锁顺序死锁不一样的地方是，竞争的资源之间并没有严格先后顺序，仅仅是相互依赖而已。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/12/29/365149.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/365149.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-12-29 14:04 <a href="http://www.blogjava.net/xylz/archive/2011/12/29/365149.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (36): 线程池 part 9 并发操作异常体系</title><link>http://www.blogjava.net/xylz/archive/2011/07/12/354206.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 12 Jul 2011 15:15:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/07/12/354206.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/354206.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/07/12/354206.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/354206.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/354206.html</trackback:ping><description><![CDATA[<p>并发包引入的工具类很多方法都会抛出一定的异常，这些异常描述了任务在线程池中执行时发生的例外情况，而通常这些例外需要应用程序进行捕捉和处理。</p>
<p>例如在Future接口中有如下一个API：</p>
<p>&nbsp;</p>
<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; ">java.util.concurrent.Future.get(</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">,&nbsp;TimeUnit)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException,&nbsp;ExecutionException,&nbsp;TimeoutException;</span></div>
<p>&nbsp;</p>
<p>在<a href="http://www.blogjava.net/xylz/archive/2011/02/13/344207.html" target="_blank">前面的章节</a>中描述了Future类的具体实现原理。这里不再讨论，但是比较好奇的抛出的三个异常。</p>
<p>这里有一篇文章（<a href="http://www.ibm.com/developerworks/cn/java/j-jtp05236.html" target="_blank">Java 理论与实践: 处理 InterruptedException</a>）描述了InterruptedException的来源和处理方式。简单的说就是线程在执行的过程中被自己或者别人中断了。这时候为了响应中断就需要处理当前的异常。</p>
<p>对于java.lang.Thread而言，InterruptedException也是一个很诡异的问题。</p>
<p>中断一个线程Thread.<strong>interrupt()</strong>时会触发下面一种情况：</p>
<blockquote>
<p>如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法，或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻，则其中断状态将被清除，它还将收到一个 InterruptedException。</p>
</blockquote>
<p>检测一个线程的中断状态描述是这样的Thread.<strong>interrupted()：</strong></p>
<blockquote>
<p>测试当前线程是否已经中断。线程的<em>中断状态</em> 由该方法清除。换句话说，如果连续两次调用该方法，则第二次调用将返回 false（在第一次调用已清除了其中断状态之后，且第二次调用检验完中断状态前，当前线程再次中断的情况除外）。&nbsp; </p>
</blockquote>
<p>也就是说如果检测到一个线程已经被中断了，那么线程的使用方（挂起、等待或者正在执行）都将应该得到一个中断异常，同时将会清除异常中断状态。</p>
<p>&nbsp;</p>
<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; ">V&nbsp;innerGet(</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;nanosTimeout)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException,&nbsp;ExecutionException,&nbsp;TimeoutException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">tryAcquireSharedNanos(</span><span style="color: #000000; ">0</span><span style="color: #000000; ">,&nbsp;nanosTimeout))<br />
&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;TimeoutException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(getState()&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;CANCELLED)<br />
&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;CancellationException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(exception&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ExecutionException(exception);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;result;<br />
}</span></div>
<p>&nbsp;</p>
<p>上面获取任务结果的方法实现中，将在获取锁的过程中得到一个中断异常。代码java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(int, long)描述了这种情况：<br />
</p>
<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; ">&nbsp; &nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;tryAcquireSharedNanos(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;arg,&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;nanosTimeout)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(Thread.interrupted())<br />
&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;InterruptedException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;tryAcquireShared(arg)&nbsp;</span><span style="color: #000000; ">&gt;=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; "><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doAcquireSharedNanos(arg,&nbsp;nanosTimeout);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p>&nbsp;</p>
<p><br />
</p>
<p>这里在获取锁的时候检测线程中断情况，如果被中断则清除中断位，同时抛出一个中断异常。为什么如此做？因为我们的线程在线程池中是被重复执行的，所以一旦线程被中断后并不会退出线程，而是设置中断位，等候任务队列自己处理线程，从而达到线程被重复利用的目的。有兴趣的可以参考代码java.util.concurrent.ThreadPoolExecutor.Worker.runTask(Runnable)。这里在关闭线程池时就会导致中断所有线程。</p>
<p>除了InterruptedException 异常我们还发现了一个全新的异常java.util.concurrent.TimeoutException，此异常是用来描述任务执行时间超过了期望等待时间，也许是一直没有获取到锁，也许是还没有执行完成。</p>
<p>在innerGet代码片段中我们看到，如果线程在指定的时间无法获取到锁，那么就会得到一个超时异常。这个很好理解，比如如果执行一个非常耗时的网络任务，我们不希望任务一直等待从而占用大量的资源，可能在一定时间后就会希望取消此操作。此时超时异常很好的描述了这种需求。</p>
<p>与此同时，如果取消了一个任务，那么再次从任务中获取执行结果，那么将会得到一个任务被取消的异常java.util.concurrent.CancellationException。</p>
<p>除了上述异常外，还将得到一个java.util.concurrent.ExecutionException异常，</p>
<p>这是因为我们的提交的任务java.util.concurrent.Callable在call()方法中允许抛出任何异常，另外常规的线程执行也可能抛出一个RuntimeException，所以这里简单包装了下所有异常，当作执行过程中发生的异常ExecutionException抛出。</p>
<p>以上就是整个异常体系，所有并发操作的异常都可以归结于上述几类。</p>
<p>很多情况下处理时间长度都是用<strong>java.util.concurrent.TimeUnit</strong>，这是一个枚举类型，用来描述时间长度。其中内置了一些长度的单位。其中包括纳秒、微秒、毫秒、秒、分、时、天。例如超时操作5秒，可以使用</p>
<p>Future.get(5,TimeUnit.SECONDS) 或者 Future.get(5000L,TimeUnit.MILLISECONDS)</p>
<p>当然一种单位的时间转换成另一种单位的时间也是非常方便的。另外还有线程的sleep/join以及对象的wait操作的便捷操作。</p>
<p>&nbsp;</p>
<div id="index">
<div id="previous"><a href="http://www.blogjava.net/xylz/archive/2011/02/13/344207.html">线程池 part 8 线程池的实现及原理 (3)</a> </div>
<div id="center" align="center"><a href="http://www.blogjava.net/xylz/archive/2010/07/08/325587.html"><strong>目&nbsp;&nbsp; 录</strong></a> </div>
<div id="next"><a href="http://www.blogjava.net/xylz/archive/2011/12/29/365149.html">并发总结 part 1 死锁与活跃度</a> </div>
</div><img src ="http://www.blogjava.net/xylz/aggbug/354206.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-07-12 23:15 <a href="http://www.blogjava.net/xylz/archive/2011/07/12/354206.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (35): 线程池 part 8 线程池的实现及原理 (3)</title><link>http://www.blogjava.net/xylz/archive/2011/02/13/344207.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Sun, 13 Feb 2011 12:21:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/02/13/344207.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/344207.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/02/13/344207.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/344207.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/344207.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本节中将探讨线程池是如何处理任务结果以及延迟、周期性任务调度是如何实现的。<br>结合上节线程池的原理和实现，彻底分析了线程池对任务的结果处理，尤其是对延迟、周期性任务是如何执行的。<br>这也是并发系列中源码分析的最后一小节。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/02/13/344207.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/344207.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-02-13 20:21 <a href="http://www.blogjava.net/xylz/archive/2011/02/13/344207.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (34): 线程池 part 7 线程池的实现及原理 (2)</title><link>http://www.blogjava.net/xylz/archive/2011/02/11/344091.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Fri, 11 Feb 2011 15:48:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/02/11/344091.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/344091.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/02/11/344091.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/344091.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/344091.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这一节中我们将详细讨论线程池是如何执行一个任务的，尤其是如何处理线程池的大小、核心大小、最大大小、任务队列等之间的关系的。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/02/11/344091.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/344091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-02-11 23:48 <a href="http://www.blogjava.net/xylz/archive/2011/02/11/344091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (33): 线程池 part 6 线程池的实现及原理 (1)</title><link>http://www.blogjava.net/xylz/archive/2011/01/18/343183.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 18 Jan 2011 15:43:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/01/18/343183.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/343183.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/01/18/343183.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/343183.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/343183.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我们根据线程池的要求也很能够猜测出其数据结构出来。<br>线程池需要支持多个线程并发执行，因此有一个线程集合Collection<Thread>来执行线程任务；<br>涉及任务的异步执行，因此需要有一个集合来缓存任务队列Collection<Runnable>；<br>很显然在多个线程之间协调多个任务，那么就需要一个线程安全的任务集合，同时还需要支持阻塞、超时操作，那么BlockingQueue是必不可少的；<br>既然是线程池，出发点就是提高系统性能同时降低资源消耗，那么线程池的大小就有限制，因此需要有一个核心线程池大小（线程个数）和一个最大线程池大小（线程个数），有一个计数用来描述当前线程池大小；<br>如果是有限的线程池大小，那么长时间不使用的线程资源就应该销毁掉，这样就需要一个线程空闲时间的计数来描述线程何时被销毁；<br>前面描述过线程池也是有生命周期的，因此需要有一个状态来描述线程池当前的运行状态；<br>线程池的任务队列如果有边界，那么就需要有一个任务拒绝策略来处理过多的任务，同时在线程池的销毁阶段也需要有一个任务拒绝策略来处理新加入的任务；<br>上面种&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/01/18/343183.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/343183.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-01-18 23:43 <a href="http://www.blogjava.net/xylz/archive/2011/01/18/343183.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (32): 线程池 part 5 周期性任务调度</title><link>http://www.blogjava.net/xylz/archive/2011/01/10/342738.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Mon, 10 Jan 2011 15:39:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/01/10/342738.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/342738.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/01/10/342738.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/342738.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/342738.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在JDK 5.0之前，java.util.Timer/TimerTask是唯一的内置任务调度方法，而且在很长一段时间里很热衷于使用这种方式进行周期性任务调度。<br>首先研究下Timer/TimerTask的特性（至于javax.swing.Timer就不再研究了）。<br>上面三段代码反映了Timer/TimerTask的以下特性：<br>Timer对任务的调度是基于绝对时间的。<br>所有的TimerTask只有一个线程TimerThread来执行，因此同一时刻只有一个TimerTask在执行。<br>任何一个TimerTask的执行异常都会导致Timer终止所有任务。<br>由于基于绝对时间并且是单线程执行，因此在多个任务调度时，长时间执行的任务被执行后有可能导致短时间任务快速在短时间内被执行多次或者干脆丢弃多个任务。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/01/10/342738.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/342738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-01-10 23:39 <a href="http://www.blogjava.net/xylz/archive/2011/01/10/342738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (31): 线程池 part 4 线程池任务拒绝策略</title><link>http://www.blogjava.net/xylz/archive/2011/01/08/342609.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Sat, 08 Jan 2011 14:47:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/01/08/342609.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/342609.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/01/08/342609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/342609.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/342609.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 上一节中提到关闭线程池过程中需要对新提交的任务进行处理。这个是java.util.concurrent.RejectedExecutionHandler处理的逻辑。<br> <br>在没有分析线程池原理之前先来分析下为什么有任务拒绝的情况发生。<br>这里先假设一个前提：线程池有一个任务队列，用于缓存所有待处理的任务，正在处理的任务将从任务队列中移除。因此在任务队列长度有限的情况下就会出现新任务的拒绝处理问题，需要有一种策略来处理应该加入任务队列却因为队列已满无法加入的情况。另外在线程池关闭的时候也需要对任务加入队列操作进行额外的协调处理。<br> <br>RejectedExecutionHandler提供了四种方式来处理任务拒绝策略。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/01/08/342609.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/342609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-01-08 22:47 <a href="http://www.blogjava.net/xylz/archive/2011/01/08/342609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (30): 线程池 part 3 Executor 生命周期</title><link>http://www.blogjava.net/xylz/archive/2011/01/04/342316.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 04 Jan 2011 14:54:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2011/01/04/342316.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/342316.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2011/01/04/342316.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/342316.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/342316.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:  <br>我们知道线程是有多种执行状态的，同样管理线程的线程池也有多种状态。JVM会在所有线程（非后台daemon线程）全部终止后才退出，为了节省资源和有效释放资源关闭一个线程池就显得很重要。有时候无法正确的关闭线程池，将会阻止JVM的结束。<br>线程池Executor是异步的执行任务，因此任何时刻不能够直接获取提交的任务的状态。这些任务有可能已经完成，也有可能正在执行或者还在排队等待执行。因此关闭线程池可能出现一下几种情况：<br>平缓关闭：已经启动的任务全部执行完毕，同时不再接受新的任务<br>立即关闭：取消所有正在执行和未执行的任务<br>另外关闭线程池后对于任务的状态应该有相应的反馈信息。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2011/01/04/342316.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/342316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2011-01-04 22:54 <a href="http://www.blogjava.net/xylz/archive/2011/01/04/342316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (29): 线程池 part 2 Executor 以及Executors</title><link>http://www.blogjava.net/xylz/archive/2010/12/21/341281.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 21 Dec 2010 15:32:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/12/21/341281.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/341281.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/12/21/341281.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/341281.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/341281.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java里面线程池的顶级接口是Executor，但是严格意义上讲Executor并不是一个线程池，而只是一个执行线程的工具。真正的线程池接口是ExecutorService。<br>下面这张图完整描述了线程池的类体系结构。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/12/21/341281.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/341281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-12-21 23:32 <a href="http://www.blogjava.net/xylz/archive/2010/12/21/341281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (28): 线程池 part 1 简介</title><link>http://www.blogjava.net/xylz/archive/2010/12/19/341098.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Sun, 19 Dec 2010 05:24:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/12/19/341098.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/341098.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/12/19/341098.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/341098.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/341098.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 从这一节开始正式进入线程池的部分。其实整个体系已经拖了很长的时间，因此后面的章节会加快速度，甚至只是一个半成品或者简单化，以后有时间的慢慢补充、完善。<br>其实线程池是并发包里面很重要的一部分，在实际情况中也是使用很多的一个重要组件。<br>下图描述的是线程池API的一部分。广义上的完整线程池可能还包括Thread/Runnable、Timer/TimerTask等部分。这里只介绍主要的和高级的API以及架构和原理。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/12/19/341098.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/341098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-12-19 13:24 <a href="http://www.blogjava.net/xylz/archive/2010/12/19/341098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (27): 并发容器 part 12 线程安全的List/Set</title><link>http://www.blogjava.net/xylz/archive/2010/11/23/338853.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 23 Nov 2010 14:22:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/11/23/338853.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/338853.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/11/23/338853.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/338853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/338853.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本小节是《并发容器》的最后一部分，这一个小节描述的是针对List/Set接口的一个线程版本。<br>在《并发队列与Queue简介》中介绍了并发容器的一个概括，主要描述的是Queue的实现。其中特别提到一点LinkedList是List/Queue的实现，但是LinkedList确实非线程安全的。不管BlockingQueue还是ConcurrentMap的实现，我们发现都是针对链表的实现，当然尽可能的使用CAS或者Lock的特性，同时都有通过锁部分容器来提供并发的特性。而对于List或者Set而言，增、删操作其实都是针对整个容器，因此每次操作都不可避免的需要锁定整个容器空间，性能肯定会大打折扣。要实现一个线程安全的List/Set，只需要在修改操作的时候进行同步即可，比如使用java.util.Collections.synchronizedList(List<T>)或者java.util.Collections.synchronizedSet(Set<T>)。当然也可以使用Lock来实现线程安全的List/Set。<br>通常情况下我们的高并发都发生在“多读少写”的情况，因此如果&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/11/23/338853.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/338853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-11-23 22:22 <a href="http://www.blogjava.net/xylz/archive/2010/11/23/338853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (26): 并发容器 part 11 Exchanger</title><link>http://www.blogjava.net/xylz/archive/2010/11/22/338733.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Mon, 22 Nov 2010 14:31:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/11/22/338733.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/338733.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/11/22/338733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/338733.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/338733.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange 方法，与伙伴线程进行匹配，并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。<br>换句话说Exchanger提供的是一个交换服务，允许原子性的交换两个（多个）对象，但同时只有一对才会成功。先看一个简单的实例模型。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/11/22/338733.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/338733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-11-22 22:31 <a href="http://www.blogjava.net/xylz/archive/2010/11/22/338733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (25): 并发容器 part 10 双向并发阻塞队列 BlockingDeque</title><link>http://www.blogjava.net/xylz/archive/2010/08/18/329227.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Wed, 18 Aug 2010 08:01:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/08/18/329227.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/329227.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/08/18/329227.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/329227.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/329227.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这个小节介绍Queue的最后一个工具，也是最强大的一个工具。从名称上就可以看到此工具的特点：双向并发阻塞队列。所谓双向是指可以从队列的头和尾同时操作，并发只是线程安全的实现，阻塞允许在入队出队不满足条件时挂起线程，这里说的队列是指支持FIFO/FILO实现的链表。<br> <br>首先看下LinkedBlockingDeque的数据结构。通常情况下从数据结构上就能看出这种实现的优缺点，这样就知道如何更好的使用工具了。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/08/18/329227.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/329227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-08-18 16:01 <a href="http://www.blogjava.net/xylz/archive/2010/08/18/329227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (24): 并发容器 part 9 双向队列集合 Deque</title><link>http://www.blogjava.net/xylz/archive/2010/08/12/328587.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Wed, 11 Aug 2010 16:13:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/08/12/328587.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/328587.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/08/12/328587.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/328587.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/328587.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:  <br>有一段时间没有更新了。接着上节继续吧。<br>Queue除了前面介绍的实现外，还有一种双向的Queue实现Deque。这种队列允许在队列头和尾部进行入队出队操作，因此在功能上比Queue显然要更复杂。下图描述的是Deque的完整体系图。需要说明的是LinkedList也已经加入了Deque的一部分（LinkedList是从jdk1.2 开始就存在数据结构）。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/08/12/328587.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/328587.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-08-12 00:13 <a href="http://www.blogjava.net/xylz/archive/2010/08/12/328587.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (23): 并发容器 part 8 可阻塞的BlockingQueue (3)</title><link>http://www.blogjava.net/xylz/archive/2010/07/30/327582.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Fri, 30 Jul 2010 08:15:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/30/327582.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/327582.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/30/327582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/327582.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/327582.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:  <br>在Set中有一个排序的集合SortedSet，用来保存按照自然顺序排列的对象。Queue中同样引入了一个支持排序的FIFO模型。<br>并发队列与Queue简介 中介绍了，PriorityQueue和PriorityBlockingQueue就是支持排序的Queue。显然一个支持阻塞的排序Queue要比一个非线程安全的Queue实现起来要复杂的多，因此下面只介绍PriorityBlockingQueue，至于PriorityQueue只需要去掉Blocking功能就基本相同了。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/30/327582.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/327582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-30 16:15 <a href="http://www.blogjava.net/xylz/archive/2010/07/30/327582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (22): 并发容器 part 7 可阻塞的BlockingQueue (2)</title><link>http://www.blogjava.net/xylz/archive/2010/07/27/327265.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 27 Jul 2010 14:04:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/27/327265.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/327265.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/27/327265.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/327265.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/327265.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在上一节中详细分析了LinkedBlockingQueue 的实现原理。实现一个可扩展的队列通常有两种方式：一种方式就像LinkedBlockingQueue一样使用链表，也就是每一个元素带有下一个元素的引用，这样的队列原生就是可扩展的；另外一种就是通过数组实现，一旦队列的大小达到数组的容量的时候就将数组扩充一倍（或者一定的系数倍），从而达到扩容的目的。常见的ArrayList就属于第二种。前面章节介绍过的HashMap确是综合使用了这两种方式。<br>对于一个Queue而言，同样可以使用数组实现。使用数组的好处在于各个元素之间原生就是通过数组的索引关联起来的，一次元素之间就是有序的，在通过索引操作数组就方便多了。当然也有它不利的一面，扩容起来比较麻烦，同时删除一个元素也比较低效。<br>ArrayBlockingQueue 就是Queue的一种数组实现。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/27/327265.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/327265.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-27 22:04 <a href="http://www.blogjava.net/xylz/archive/2010/07/27/327265.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (21): 并发容器 part 6 可阻塞的BlockingQueue (1)</title><link>http://www.blogjava.net/xylz/archive/2010/07/24/326988.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Fri, 23 Jul 2010 16:02:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/24/326988.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326988.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/24/326988.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326988.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326988.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在《并发容器 part 4 并发队列与Queue简介》节中的类图中可以看到，对于Queue来说，BlockingQueue是主要的线程安全版本。这是一个可阻塞的版本，也就是允许添加/删除元素被阻塞，直到成功为止。<br>BlockingQueue相对于Queue而言增加了两个操作：put/take。下面是一张整理的表格。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/24/326988.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326988.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-24 00:02 <a href="http://www.blogjava.net/xylz/archive/2010/07/24/326988.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (20): 并发容器 part 5 ConcurrentLinkedQueue</title><link>http://www.blogjava.net/xylz/archive/2010/07/23/326934.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Fri, 23 Jul 2010 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/23/326934.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326934.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/23/326934.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326934.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326934.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: ConcurrentLinkedQueue是Queue的一个线程安全实现。先来看一段文档说明。<br>一个基于链接节点的无界线程安全队列。此队列按照 FIFO（先进先出）原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部，队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时，ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。<br> <br>由于ConcurrentLinkedQueue只是简单的实现了一个队列Queue，因此从API的角度讲，没有多少值的介绍，使用起来也很简单，和前面遇到的所有FIFO队列都类似。出队列只能操作头节点，入队列只能操作尾节点，任意节点操作就需要遍历完整的队列。<br>重点放在解释ConcurrentLinkedQueue的原理和实现上。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/23/326934.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-23 14:11 <a href="http://www.blogjava.net/xylz/archive/2010/07/23/326934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (19): 并发容器 part 4 并发队列与Queue简介</title><link>http://www.blogjava.net/xylz/archive/2010/07/21/326723.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Wed, 21 Jul 2010 04:21:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/21/326723.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326723.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/21/326723.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326723.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326723.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Queue是JDK 5以后引入的新的集合类，它属于Java Collections Framework的成员，在Collection集合中和List/Set是同一级别的接口。通常来讲Queue描述的是一种FIFO的队列，当然不全都是，比如PriorityQueue是按照优先级的顺序（或者说是自然顺序，借助于Comparator接口）。<br>下图描述了Java Collections Framework中Queue的整个家族体系。<br>对于Queue而言是在Collection的基础上增加了offer/remove/poll/element/peek方法，另外重新定义了add方法。对于这六个方法，有不同的定义。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/21/326723.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-21 12:21 <a href="http://www.blogjava.net/xylz/archive/2010/07/21/326723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (18): 并发容器 part 3 ConcurrentMap (3)</title><link>http://www.blogjava.net/xylz/archive/2010/07/20/326661.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Tue, 20 Jul 2010 09:48:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/20/326661.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326661.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/20/326661.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326661.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326661.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在上一篇中介绍了HashMap的原理，这一节是ConcurrentMap的最后一节，所以会完整的介绍ConcurrentHashMap的实现。<br> <br>ConcurrentHashMap原理<br> <br>在读写锁章节部分介绍过一种是用读写锁实现Map的方法。此种方法看起来可以实现Map响应的功能，而且吞吐量也应该不错。但是通过前面对读写锁原理的分析后知道，读写锁的适合场景是读操作>>写操作，也就是读操作应该占据大部分操作，另外读写锁存在一个很严重的问题是读写操作不能同时发生。要想解决读写同时进行问题（至少不同元素的读写分离），那么就只能将锁拆分，不同的元素拥有不同的锁，这种技术就是“锁分离”技术。<br>默认情况下ConcurrentHashMap是用了16个类似HashMap 的结构，其中每一个HashMap拥有一个独占锁。也就是说最终的效果就是通过某种Hash算法，将任何一个元素均匀的映射到某个HashMap的Map.Entry上面，而对某个一个元素的操作就集中在其分布的HashMap上，与其它HashMap无关。这样就支持最多16个并发的写操作。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/20/326661.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326661.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-20 17:48 <a href="http://www.blogjava.net/xylz/archive/2010/07/20/326661.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (17): 并发容器 part 2 ConcurrentMap (2)</title><link>http://www.blogjava.net/xylz/archive/2010/07/20/326584.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Mon, 19 Jul 2010 16:22:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/20/326584.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326584.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/20/326584.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326584.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326584.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本来想比较全面和深入的谈谈ConcurrentHashMap的，发现网上有很多对HashMap和ConcurrentHashMap分析的文章，因此本小节尽可能的分析其中的细节，少一点理论的东西，多谈谈内部设计的原理和思想。<br>要谈ConcurrentHashMap的构造，就不得不谈HashMap的构造，因此先从HashMap开始简单介绍。<br> <br>HashMap原理<br>我们从头开始设想。要将对象存放在一起，如何设计这个容器。目前只有两条路可以走，一种是采用分格技术，每一个对象存放于一个格子中，这样通过对格子的编号就能取到或者遍历对象；另一种技术就是采用串联的方式，将各个对象串联起来，这需要各个对象至少带有下一个对象的索引（或者指针）。显然第一种就是数组的概念，第二种就是链表的概念。所有的容器的实现其实都是基于这两种方式的，不管是数组还是链表，或者二者俱有。HashMap采用的就是数组的方式。<br>有了存取对象的容器后还需要以下两个条件才能完成Map所需要的条件。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/20/326584.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-20 00:22 <a href="http://www.blogjava.net/xylz/archive/2010/07/20/326584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (16): 并发容器 part 1 ConcurrentMap (1)</title><link>http://www.blogjava.net/xylz/archive/2010/07/19/326527.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Mon, 19 Jul 2010 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/19/326527.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326527.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/19/326527.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326527.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326527.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 从这一节开始正式进入并发容器的部分，来看看JDK 6带来了哪些并发容器。<br>在JDK 1.4以下只有Vector和Hashtable是线程安全的集合（也称并发容器，Collections.synchronized*系列也可以看作是线程安全的实现）。从JDK 5开始增加了线程安全的Map接口ConcurrentMap和线程安全的队列BlockingQueue（尽管Queue也是同时期引入的新的集合，但是规范并没有规定一定是线程安全的，事实上一些实现也不是线程安全的，比如PriorityQueue、ArrayDeque、LinkedList等，在Queue章节中会具体讨论这些队列的结构图和实现）。<br> <br>在介绍ConcurrencyMap之前先来回顾下Map的体系结构。下图描述了Map的体系结构，其中蓝色字体的是JDK 5以后新增的并发容器。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/19/326527.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-19 15:25 <a href="http://www.blogjava.net/xylz/archive/2010/07/19/326527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题</title><link>http://www.blogjava.net/xylz/archive/2010/07/16/326246.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Thu, 15 Jul 2010 16:15:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/16/326246.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/326246.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/16/326246.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/326246.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/326246.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:  <br>主要谈谈锁的性能以及其它一些理论知识，内容主要的出处是《Java Concurrency in Practice》，结合自己的理解和实际应用对锁机制进行一个小小的总结。<br> <br>首先需要强调的一点是：所有锁（包括内置锁和高级锁）都是有性能消耗的，也就是说在高并发的情况下，由于锁机制带来的上下文切换、资源同步等消耗是非常可观的。在某些极端情况下，线程在锁上的消耗可能比线程本身的消耗还要多。所以如果可能的话，在任何情况下都尽量少用锁，如果不可避免那么采用非阻塞算法是一个不错的解决方案，但是却也不是绝对的。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/16/326246.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/326246.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-16 00:15 <a href="http://www.blogjava.net/xylz/archive/2010/07/16/326246.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《深入浅出 Java Concurrency》目录</title><link>http://www.blogjava.net/xylz/archive/2010/07/08/325587.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Thu, 08 Jul 2010 11:17:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/08/325587.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/325587.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/08/325587.html#Feedback</comments><slash:comments>33</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/325587.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/325587.html</trackback:ping><description><![CDATA[<p>这是一份完整的Java 并发整理笔记，记录了我最近几年学习Java并发的一些心得和体会。</p>
<p>&nbsp;</p>
<ol>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/06/30/324915.html">J.U.C 整体认识</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/01/324988.html">原子操作 part 1 从AtomicInteger开始</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/02/325079.html">原子操作 part 2 数组、引用的原子操作</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/03/325168.html">原子操作 part 3 指令重排序与happens-before法则</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/04/325206.html">原子操作 part 4 CAS操作</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/05/325274.html">锁机制 part 1 Lock与ReentrantLock</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/06/325390.html">锁机制 part 2 AQS </a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/07/325410.html">锁机制 part 3 加锁的原理 (Lock.lock)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/08/325540.html">锁机制 part 4 锁释放与条件变量 (Lock.unlock And Condition)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/09/325612.html">锁机制 part 5 闭锁 (CountDownLatch)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/12/325913.html">锁机制 part 6 CyclicBarrier</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/13/326021.html">锁机制 part 7 信号量 (Semaphore)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/14/326080.html">锁机制 part 8 读写锁 (ReentrantReadWriteLock) (1)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/15/326152.html">锁机制 part 9 读写锁 (ReentrantReadWriteLock) (2)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/16/326246.html">锁机制 part 10 锁的一些其它问题</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/19/326527.html">并发容器 part 1 ConcurrentMap (1)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/20/326584.html">并发容器 part 2 ConcurrentMap (2)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/20/326661.html">并发容器 part 3 ConcurrentMap (3)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/21/326723.html">并发容器 part 4 并发队列与Queue简介</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/23/326934.html">并发容器 part 5 ConcurrentLinkedQueue </a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/24/326988.html">并发容器 part 6 可阻塞的BlockingQueue (1)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/27/327265.html">并发容器 part 7 可阻塞的BlockingQueue (2)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/07/30/327582.html">并发容器 part 8 可阻塞的BlockingQueue (3)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/08/12/328587.html">并发容器 part 9 双向队列集合 Deque</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/08/18/329227.html">并发容器 part 10 双向并发阻塞队列 BlockingDeque</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/11/22/338733.html">并发容器 part 11 Exchanger</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/11/23/338853.html">并发容器 part 12 线程安全的List/Set CopyOnWriteArrayList/CopyOnWriteArraySet</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/12/19/341098.html">线程池 part 1 简介</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2010/12/21/341281.html">线程池 part 2 Executor 以及Executors</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/01/04/342316.html">线程池 part 3 Executor 生命周期</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/01/08/342609.html">线程池 part 4 线程池任务拒绝策略</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/01/10/342738.html">线程池 part 5 周期性任务调度</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/01/18/343183.html">线程池 part 6 线程池的实现及原理 (1)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/02/11/344091.html">线程池 part 7 线程池的实现及原理 (2)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/02/13/344207.html">线程池 part 8 线程池的实现及原理 (3)</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/07/12/354206.html">线程池 part 9 并发操作异常体系</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/12/29/365149.html">并发总结 part 1 死锁与活跃度</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/12/29/367480.html">并发总结 part 2 常见的并发场景</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/12/30/367592.html">并发总结 part 3 常见的并发陷阱</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2011/12/31/367641.html">并发总结 part 4&nbsp; 性能与伸缩性</a></li>
     <li><a href="http://www.blogjava.net/xylz/archive/2013/08/05/402405.html">捕获Java线程池执行任务抛出的异常</a></li>
</ol>
<p>&nbsp;</p>
<div id="index">
<div id="previous"></div>
<div id="center" align="center"></div>
<div id="next"><a href="http://www.blogjava.net/xylz/archive/2010/06/30/324915.html">J.U.C的整体认识</a></div>
<a href="http://www.blogjava.net/xylz/archive/2010/06/30/324915.html">
</a></div>
<a href="http://www.blogjava.net/xylz/archive/2010/06/30/324915.html">
<p>&nbsp;</p>
<p>最后更新时间： 2013-08-05 16:47</p>
</a><img src ="http://www.blogjava.net/xylz/aggbug/325587.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-08 19:17 <a href="http://www.blogjava.net/xylz/archive/2010/07/08/325587.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则</title><link>http://www.blogjava.net/xylz/archive/2010/07/03/325168.html</link><dc:creator>imxylz</dc:creator><author>imxylz</author><pubDate>Sat, 03 Jul 2010 12:40:00 GMT</pubDate><guid>http://www.blogjava.net/xylz/archive/2010/07/03/325168.html</guid><wfw:comment>http://www.blogjava.net/xylz/comments/325168.html</wfw:comment><comments>http://www.blogjava.net/xylz/archive/2010/07/03/325168.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.blogjava.net/xylz/comments/commentRss/325168.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xylz/services/trackbacks/325168.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在这个小结里面重点讨论原子操作的原理和设计思想。<br>由于在下一个章节中会谈到锁机制，因此此小节中会适当引入锁的概念。<br>在Java Concurrency in Practice中是这样定义线程安全的：<br>当多个线程访问一个类时，如果不用考虑这些线程在运行时环境下的调度和交替运行，并且不需要额外的同步及在调用方代码不必做其他的协调，这个类的行为仍然是正确的，那么这个类就是线程安全的。&nbsp;&nbsp;<a href='http://www.blogjava.net/xylz/archive/2010/07/03/325168.html'>阅读全文</a><img src ="http://www.blogjava.net/xylz/aggbug/325168.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xylz/" target="_blank">imxylz</a> 2010-07-03 20:40 <a href="http://www.blogjava.net/xylz/archive/2010/07/03/325168.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>