﻿<?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-Roy's Blog-随笔分类-java并发</title><link>http://www.blogjava.net/RoyPayne/category/50470.html</link><description>－敲击思想的键盘，滑动灵感的鼠标。</description><language>zh-cn</language><lastBuildDate>Wed, 12 Dec 2012 11:31:57 GMT</lastBuildDate><pubDate>Wed, 12 Dec 2012 11:31:57 GMT</pubDate><ttl>60</ttl><item><title>编写多线程Java应用中的死锁问题</title><link>http://www.blogjava.net/RoyPayne/archive/2012/12/10/392713.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Mon, 10 Dec 2012 02:54:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2012/12/10/392713.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/392713.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2012/12/10/392713.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/392713.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/392713.html</trackback:ping><description><![CDATA[<div>&nbsp; &nbsp; &nbsp; 死锁是一个经典的多线程问题，因为不同的线程都在等待那些根本不可能被释放的锁，</div><div>从而导致所有的工作都无法完成。假设有两个线程，分别代表两个饥饿的人，他们必须共享刀叉并轮流吃饭。</div><div>他们都需要获得两个锁：共享刀和共享叉的锁。假如线程 "A" 获得了刀，而线程 "B" 获得了叉。</div><div>线程 A 就会进入阻塞状态来等待获得叉，而线程 B 则阻塞来等待 A 所拥有的刀。<br />&nbsp; &nbsp; &nbsp;&nbsp;<br /><div>&nbsp; &nbsp; &nbsp; 让所有的线程按照同样的顺序获得一组锁。这种方法消除了 X 和 Y 的拥有者分别等待对方的资源的问题。</div><div>　　将多个锁组成一组并放到同一个锁下。前面死锁的例子中，可以创建一个银器对象的锁。于是在获得刀或叉之前都必须获得这个银器的锁。</div><div>　　将那些不会阻塞的可获得资源用变量标志出来。当某个线程获得银器对象的锁时，就可以通过检查变量来判断是否整个银器集合中的对象锁都可获得。如果是，它就可以获得相关的锁，否则，就要释放掉银器这个锁并稍后再尝试。</div><div>　　最重要的是，在编写代码前认真仔细地设计整个系统。多线程是困难的，在开始编程之前详细设计系统能够帮助你避免难以发现死锁的问题。</div></div><img src ="http://www.blogjava.net/RoyPayne/aggbug/392713.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2012-12-10 10:54 <a href="http://www.blogjava.net/RoyPayne/archive/2012/12/10/392713.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.ConcurrentModificationException</title><link>http://www.blogjava.net/RoyPayne/archive/2012/01/06/368024.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Fri, 06 Jan 2012 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2012/01/06/368024.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/368024.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2012/01/06/368024.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/368024.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/368024.html</trackback:ping><description><![CDATA[<div><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">工作中碰到个ConcurrentModificationException。代码如下：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="box-sizing: border-box; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; color: #0000ff; ">List list = ...;<br style="box-sizing: border-box; " />for(Iterator iter = list.iterator(); iter.hasNext();) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; Object obj = iter.next();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; ...<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; if(***) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.remove(obj);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />}<br style="box-sizing: border-box; " /></span><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">在执行了remove方法之后，再去执行循环，iter.next()的时候，报java.util.ConcurrentModificationException(当然，如果remove的是最后一条，就不会再去执行next()操作了)</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">下面来看一下源码</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="box-sizing: border-box; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; color: #0000ff; ">public interface Iterator&lt;E&gt; {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; boolean hasNext();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; E next();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; void remove();<br style="box-sizing: border-box; " />}<br style="box-sizing: border-box; " /><br style="box-sizing: border-box; " />public interface Collection&lt;E&gt; extends Iterable&lt;E&gt; {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; ...<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; Iterator&lt;E&gt; iterator();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; boolean add(E o);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; boolean remove(Object o);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; ...<br style="box-sizing: border-box; " />}</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">这里有两个remove方法</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">接下来来看看AbstractList</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="box-sizing: border-box; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; color: #0000ff; ">public abstract class AbstractList&lt;E&gt; extends AbstractCollection&lt;E&gt; implements List&lt;E&gt; {&nbsp;&nbsp;<br style="box-sizing: border-box; " />//AbstractCollection和List都继承了Collection<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; protected transient int modCount = 0;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; private class Itr implements Iterator&lt;E&gt; {&nbsp; //内部类Itr<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int cursor = 0;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int lastRet = -1;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int expectedModCount = modCount;<br style="box-sizing: border-box; " /><br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public boolean hasNext() {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return cursor != size();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " /><br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public E next() {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkForComodification();&nbsp;&nbsp;<span style="box-sizing: border-box; color: #ff0000; ">//特别注意这个方法<br style="box-sizing: border-box; " /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E next = get(cursor);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lastRet = cursor++;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return next;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch(IndexOutOfBoundsException e) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkForComodification();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new NoSuchElementException();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " /><br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void remove() {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lastRet == -1)<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalStateException();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkForComodification();<br style="box-sizing: border-box; " /><br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractList.this.remove(lastRet);&nbsp;&nbsp;<span style="box-sizing: border-box; color: #ff0000; ">//执行remove对象的操作<br style="box-sizing: border-box; " /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lastRet &lt; cursor)<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cursor--;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lastRet = -1;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expectedModCount = modCount;&nbsp;&nbsp;<span style="box-sizing: border-box; color: #ff0000; ">//重新设置了expectedModCount的值，避免了ConcurrentModificationException的产生<br style="box-sizing: border-box; " /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch(IndexOutOfBoundsException e) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ConcurrentModificationException();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " /><br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final void checkForComodification() {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (modCount != expectedModCount)&nbsp;&nbsp;<span style="box-sizing: border-box; color: #ff0000; ">//当expectedModCount和modCount不相等时，就抛出ConcurrentModificationException</span><br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ConcurrentModificationException();<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;<br style="box-sizing: border-box; " />}</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">remove(Object o)在ArrayList中实现如下：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="box-sizing: border-box; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; color: #0000ff; ">public boolean remove(Object o) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; if (o == null) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int index = 0; index &lt; size; index++)<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (elementData[index] == null) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fastRemove(index);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return true;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; } else {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int index = 0; index &lt; size; index++)<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (o.equals(elementData[index])) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fastRemove(index);<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; }<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; return false;<br style="box-sizing: border-box; " />}<br style="box-sizing: border-box; " />private void fastRemove(int index) {<br style="box-sizing: border-box; " />&nbsp;&nbsp;&nbsp; modCount++;&nbsp;&nbsp;<span style="box-sizing: border-box; color: #ff0000; ">//只增加了modCount<br style="box-sizing: border-box; " /></span>&nbsp;&nbsp;&nbsp; ....<br style="box-sizing: border-box; " />}<br style="box-sizing: border-box; " /><span style="box-sizing: border-box; color: #339966; "><br style="box-sizing: border-box; " /><strong style="box-sizing: border-box; color: #800000; ">所以，产生ConcurrentModificationException的原因就是：<br style="box-sizing: border-box; " />执行remove(Object o)方法之后，modCount和expectedModCount不相等了。然后当代码执行到next()方法时，判断了checkForComodification()，发现两个数值不等，就抛出了该Exception。<br style="box-sizing: border-box; " />要避免这个Exception，就应该使用remove()方法。</strong></span><strong style="box-sizing: border-box; "><br style="box-sizing: border-box; " /></strong></span><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">这里我们就不看add(Object o)方法了，也是同样的原因，但没有对应的add()方法。一般嘛，就另建一个List了</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">下面是网上的其他解释，更能从本质上解释原因：</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">Iterator 是工作在一个独立的线程中，并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表，当原来的对象数量发生变化时，这个索引表的内容不会同步改变，所以当索引指针往后移动的时候就找不到要迭代的对象，所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。</span><br style="box-sizing: border-box; color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; " /><span style="color: #4b4b4b; font-family: verdana, Arial, helvetica, sans-seriff; font-size: 14px; background-color: #ffffff; ">所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象， Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。</span></div><img src ="http://www.blogjava.net/RoyPayne/aggbug/368024.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2012-01-06 17:14 <a href="http://www.blogjava.net/RoyPayne/archive/2012/01/06/368024.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程----BlockingQueue (转)</title><link>http://www.blogjava.net/RoyPayne/archive/2012/01/06/368018.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Fri, 06 Jan 2012 08:32:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2012/01/06/368018.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/368018.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2012/01/06/368018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/368018.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/368018.html</trackback:ping><description><![CDATA[<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span>&nbsp;java.util.concurrent.ArrayBlockingQueue;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.util.concurrent.BlockingQueue;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.util.concurrent.ExecutorService;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.util.concurrent.Executors;<br />&nbsp;<br /><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;本例介绍一个特殊的队列:BlockingQueue,如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒.同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作.<br />&nbsp;&nbsp;&nbsp;&nbsp;本例再次实现11.4线程----条件Condition中介绍的篮子程序,不过这个篮子中最多能放的苹果数不是1,可以随意指定.当篮子满时,生产者进入等待状态,当篮子空时,消费者等待.<br />&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;使用BlockingQueue的关键技术点如下:<br />&nbsp;&nbsp;&nbsp;&nbsp;1.BlockingQueue定义的常用方法如下:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)add(anObject):把anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则招聘异常<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3)put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4)poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5)take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止<br />&nbsp;&nbsp;&nbsp;&nbsp;2.BlockingQueue有四个具体的实现类,根据不同需求,选择不同的实现类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3)PriorityBlockingQueue:类似于LinkedBlockQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4)SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的.<br />&nbsp;&nbsp;&nbsp;&nbsp;3.LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;BlockingQueueTest&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; ">定义装苹果的篮子</span><span style="color: #008000; ">*/</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Basket{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">篮子,能够容纳3个苹果</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueue&lt;String&gt;&nbsp;basket&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;ArrayBlockingQueue&lt;String&gt;(3);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">生产苹果,放入篮子</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;produce()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;InterruptedException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">put方法放入一个苹果,若basket满了,等到basket有位置</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;basket.put("An&nbsp;apple");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">消费苹果,从篮子中取走</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;consume()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;InterruptedException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">take方法取出一个苹果,若basket为空,等到basket有苹果为止</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;basket.take();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">测试方法</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;testBasket(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Basket&nbsp;basket&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Basket();<span style="color: #008000; ">//</span><span style="color: #008000; ">建立一个装苹果的篮子<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">定义苹果生产者</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Producer&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;Runnable{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(<span style="color: #0000FF; ">true</span>){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">生产苹果</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("生产者准备生产苹果:&nbsp;"&nbsp;+&nbsp;System.currentTimeMillis());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;basket.produce();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("生产者生产苹果完毕:&nbsp;"&nbsp;+&nbsp;System.currentTimeMillis());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">休眠300ms</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(300);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">catch</span>(InterruptedException&nbsp;ex){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">定义苹果消费者</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Consumer&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;Runnable{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(<span style="color: #0000FF; ">true</span>){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">消费苹果</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("消费者准备消费苹果:&nbsp;"&nbsp;+&nbsp;System.currentTimeMillis());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;basket.consume();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("消费者消费苹果完毕:&nbsp;"&nbsp;+&nbsp;System.currentTimeMillis());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">休眠1000ms</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(1000);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">catch</span>(InterruptedException&nbsp;ex){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;service&nbsp;=&nbsp;Executors.newCachedThreadPool();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Producer&nbsp;producer&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Producer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Consumer&nbsp;consumer&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Consumer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;service.submit(producer);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;service.submit(consumer);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">程序运行5s后,所有任务停止</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(5000);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">catch</span>(InterruptedException&nbsp;ex){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;service.shutdownNow();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockingQueueTest.testBasket();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><img src ="http://www.blogjava.net/RoyPayne/aggbug/368018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2012-01-06 16:32 <a href="http://www.blogjava.net/RoyPayne/archive/2012/01/06/368018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在java中正确使用volatile</title><link>http://www.blogjava.net/RoyPayne/archive/2012/01/06/367989.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Fri, 06 Jan 2012 02:44:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2012/01/06/367989.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/367989.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2012/01/06/367989.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/367989.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/367989.html</trackback:ping><description><![CDATA[<div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　 &nbsp;Java? 语言包含两种内在的同步机制：同步块（或方法）和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差（但有时它更简单并且开销更低），而且其使用也更容易出错。在这期的&nbsp;</span><em style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">Java 理论与实践</em><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">中，Brian Goetz 将介绍几种正确使用 volatile 变量的模式，并针对其适用性限制提出一些建议。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　Java 语言中的 volatile 变量可以被看作是一种 &#8220;程度较轻的 synchronized&#8221;；与 synchronized 块相比，volatile 变量所需的编码较少，并且运行时开销也较少，但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式，并强调了几种不适合使用 volatile 变量的情形。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　锁提供了两种主要特性：</span><em style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">互斥（mutual exclusion）</em><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">和</span><em style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">可见性（visibility）</em><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">。互斥即一次只允许一个线程持有某个特定的锁，因此可使用该特性实现对共享数据的协调访问协议，这样，一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些，它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 &#8212;&#8212; 如果没有同步机制提供的这种可见性保证，线程看到的共享变量可能是修改前的值或不一致的值，这将引发许多严重问题。</span><h3><a name="2_2" style="text-decoration: underline; color: rgb(19, 110, 194); "></a>Volatile 变量</h3><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　Volatile 变量具有 synchronized 的可见性特性，但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全，但是只能应用于非常有限的一组用例：多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此，单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式（Invariants）的类（例如 &#8220;start &lt;=end&#8221;）。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　出于简易性或可伸缩性的考虑，您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时，某些习惯用法（idiom）更加易于编码和阅读。此外，volatile 变量不会像锁那样造成线程阻塞，因此也很少造成可伸缩性问题。在某些情况下，如果读操作远远大于写操作，volatile 变量还可以提供优于锁的性能优势。</span><h3><a name="2_3" style="text-decoration: underline; color: rgb(19, 110, 194); "></a>正确使用 volatile 变量的条件</h3><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全，必须同时满足下面两个条件：</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　&#9679; 对变量的写操作不依赖于当前值。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　&#9679; 该变量没有包含在具有其他变量的不变式中。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　实际上，这些条件表明，可以被写入 volatile 变量的这些有效值独立于任何程序的状态，包括变量的当前状态。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作（x++）看上去类似一个单独操作，实际上它是一个由读取－修改－写入操作序列组成的组合操作，必须以原子方式执行，而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变，而 volatile 变量无法实现这点。（然而，如果将值调整为只从单个线程写入，那么可以忽略第一个条件。）</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; font-family: arial, 宋体, sans-serif; background-color: #ffffff; "></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; ">　　大多数编程情形都会与这两个条件的其中之一冲突，使得 volatile 变量不能像 synchronized 那样普遍适用于实现线程安全。清单 1 显示了一个非线程安全的数值范围类。它包含了一个不变式 &#8212;&#8212; 下界总是小于或等于上界。<br />&nbsp; &nbsp; &nbsp; &nbsp;<br />&nbsp; &nbsp; &nbsp; &nbsp;</span><strong style="font-size: 14px; ">清单 1. 非线程安全的数值范围类</strong><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><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 />-->@NotThreadSafe&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;NumberRange&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;lower,&nbsp;upper;&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getLower()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;lower;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getUpper()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;upper;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setLower(<span style="color: #0000FF; ">int</span>&nbsp;value)&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">if</span>&nbsp;(value&nbsp;&gt;&nbsp;upper)&nbsp;<br /><span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;IllegalArgumentException(<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />);&nbsp;<br />lower&nbsp;=&nbsp;value;&nbsp;<br />}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setUpper(<span style="color: #0000FF; ">int</span>&nbsp;value)&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">if</span>&nbsp;(value&nbsp;&lt;&nbsp;lower)&nbsp;<br /><span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;IllegalArgumentException(<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />);&nbsp;<br />upper&nbsp;=&nbsp;value;&nbsp;<br />}&nbsp;<br />}</div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><div><span style="font-size: 14px; ">这种方式限制了范围的状态变量，因此将 lower 和 upper 字段定义为 volatile 类型不能够充分实现类的线程安全；从而仍然需要使用同步。否则，如果凑巧两个线程在同一时间使用不一致的值执行 setLower 和 setUpper 的话，则会使范围处于不一致的状态。例如，如果初始状态是 (0, 5)，同一时间内，线程 A 调用 setLower(4) 并且线程 B 调用 setUpper(3)，显然这两个操作交叉存入的值是不符合条件的，那么两个线程都会通过用于保护不变式的检查，使得最后的范围值是 (4, 3) &#8212;&#8212; 一个无效值。至于针对范围的其他操作，我们需要使 setLower() 和 setUpper() 操作原子化 &#8212;&#8212; 而将字段定义为 volatile 类型是无法实现这一目的的。</span></div><div><h3>性能考虑</h3><span style="font-size: 14px; ">　　使用 volatile 变量的主要原因是其简易性：在某些情形下，使用 volatile 变量要比使用相应的锁简单得多。使用 volatile 变量次要原因是其性能：某些情况下，volatile 变量同步机制的性能要优于锁。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　很难做出准确、全面的评价，例如 &#8220;X 总是比 Y 快&#8221;，尤其是对 JVM 内在的操作而言。（例如，某些情况下 VM 也许能够完全删除锁机制，这使得我们难以抽象地比较 volatile和 synchronized 的开销。）就是说，在目前大多数的处理器架构上，volatile 读操作开销非常低 &#8212;&#8212; 几乎和非 volatile 读操作一样。而 volatile 写操作的开销要比非 volatile 写操作多很多，因为要保证可见性需要实现内存界定（Memory Fence），即便如此，volatile 的总开销仍然要比锁获取低。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　volatile 操作不会像锁一样造成阻塞，因此，在能够安全使用 volatile 的情况下，volatile 可以提供一些优于锁的可伸缩特性。如果读操作的次数要远远超过写操作，与锁相比，volatile 变量通常能够减少同步的性能开销。</span><h3><a name="2_5" style="text-decoration: underline; color: rgb(19, 110, 194); "></a>正确使用 volatile 的模式</h3><span style="font-size: 14px; ">　　很多并发性专家事实上往往引导用户远离 volatile 变量，因为使用它们要比使用锁更加容易出错。然而，如果谨慎地遵循一些良好定义的模式，就能够在很多场合内安全地使用 volatile 变量。要始终牢记使用 volatile 的限制 &#8212;&#8212; 只有在状态真正独立于程序内其他内容时才能使用 volatile &#8212;&#8212; 这条规则能够避免将这些模式扩展到不安全的用例。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">模式 #1：状态标志</strong><span style="font-size: 14px; ">&nbsp;也许实现 volatile 变量的规范使用仅仅是使用一个布尔状态标志，用于指示发生了一个重要的一次性事件，例如完成初始化或请求停机。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　很多应用程序包含了一种控制结构，形式为 &#8220;在还没有准备好停止程序时再执行一些工作&#8221;，如清单 2 所示：</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">清单 2. 将 volatile 变量作为状态标志使用</strong></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><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;shutdownRequested;&nbsp;<br /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" />&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;shutdown()&nbsp;{&nbsp;shutdownRequested&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;doWork()&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">while</span>&nbsp;(!shutdownRequested)&nbsp;{&nbsp;<br /><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;do&nbsp;stuff&nbsp;</span><span style="color: #008000; "><br /></span>}&nbsp;<br />}</div><div><span style="font-size: 14px; ">很可能会从循环外部调用 shutdown() 方法 &#8212;&#8212; 即在另一个线程中 &#8212;&#8212; 因此，需要执行某种同步来确保正确实现 shutdownRequested 变量的可见性。（可能会从 JMX 侦听程序、GUI 事件线程中的操作侦听程序、通过 RMI 、通过一个 Web 服务等调用）。然而，使用 synchronized 块编写循环要比使用清单 2 所示的 volatile 状态标志编写麻烦很多。由于 volatile 简化了编码，并且状态标志并不依赖于程序内任何其他状态，因此此处非常适合使用 volatile。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　这种类型的状态标记的一个公共特性是：通常只有一种状态转换；shutdownRequested 标志从 false 转换为 true，然后程序停止。这种模式可以扩展到来回转换的状态标志，但是只有在转换周期不被察觉的情况下才能扩展（从 false 到 true，再转换到 false）。此外，还需要某些原子状态转换机制，例如原子变量。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">模式 #2：一次性安全发布（one-time safe publication）</strong><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　缺乏同步会导致无法实现可见性，这使得确定何时写入对象引用而不是原语值变得更加困难。在缺乏同步的情况下，可能会遇到某个对象引用的更新值（由另一个线程写入）和该对象状态的旧值同时存在。（这就是造成著名的双重检查锁定（double-checked-locking）问题的根源，其中对象引用在没有同步的情况下进行读操作，产生的问题是您可能会看到一个更新的引用，但是仍然会通过该引用看到不完全构造的对象）。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　实现安全发布对象的一种技术就是将对象引用定义为 volatile 类型。清单 3 展示了一个示例，其中后台线程在启动阶段从数据库加载一些数据。其他代码在能够利用这些数据时，在使用之前将检查这些数据是否曾经发布过。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">清单 3. 将 volatile 变量用于一次性安全发布</strong></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><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;BackgroundFloobleLoader&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">volatile</span>&nbsp;Flooble&nbsp;theFlooble;&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;initInBackground()&nbsp;{&nbsp;<br /><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;do&nbsp;lots&nbsp;of&nbsp;stuff&nbsp;</span><span style="color: #008000; "><br /></span>theFlooble&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Flooble();&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;this&nbsp;is&nbsp;the&nbsp;only&nbsp;write&nbsp;to&nbsp;theFlooble&nbsp;</span><span style="color: #008000; "><br /></span>}&nbsp;<br />}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;SomeOtherClass&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;doWork()&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">while</span>&nbsp;(<span style="color: #0000FF; ">true</span>)&nbsp;{&nbsp;<br /><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;do&nbsp;some&nbsp;stuff<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;use&nbsp;the&nbsp;Flooble,&nbsp;but&nbsp;only&nbsp;if&nbsp;it&nbsp;is&nbsp;ready&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">if</span>&nbsp;(floobleLoader.theFlooble&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;<br />doSomething(floobleLoader.theFlooble);&nbsp;<br />}&nbsp;<br />}&nbsp;<br />}</div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><div><span style="font-size: 14px; ">如果 theFlooble 引用不是 volatile 类型，doWork() 中的代码在解除对 theFlooble 的引用时，将会得到一个不完全构造的 Flooble。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　该模式的一个必要条件是：被发布的对象必须是线程安全的，或者是有效的不可变对象（有效不可变意味着对象的状态在发布之后永远不会被修改）。volatile 类型的引用可以确保对象的发布形式的可见性，但是如果对象的状态在发布后将发生更改，那么就需要额外的同步。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">模式 #3：独立观察（independent observation）</strong><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　安全使用 volatile 的另一种简单模式是：定期 &#8220;发布&#8221; 观察结果供程序内部使用。例如，假设有一种环境传感器能够感觉环境温度。一个后台线程可能会每隔几秒读取一次该传感器，并更新包含当前文档的 volatile 变量。然后，其他线程可以读取这个变量，从而随时能够看到最新的温度值。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　使用该模式的另一种应用程序就是收集程序的统计信息。清单 4 展示了身份验证机制如何记忆最近一次登录的用户的名字。将反复使用 lastUser 引用来发布值，以供程序的其他部分使用。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　清单 4. 将 volatile 变量用于多个独立观察结果的发布</span></div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;UserManager&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">volatile</span>&nbsp;String&nbsp;lastUser;&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;authenticate(String&nbsp;user,&nbsp;String&nbsp;password)&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">boolean</span>&nbsp;valid&nbsp;=&nbsp;passwordIsValid(user,&nbsp;password);&nbsp;<br /><span style="color: #0000FF; ">if</span>&nbsp;(valid)&nbsp;{&nbsp;<br />User&nbsp;u&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;User();&nbsp;<br />activeUsers.add(u);&nbsp;<br />lastUser&nbsp;=&nbsp;user;&nbsp;<br />}&nbsp;<br /><span style="color: #0000FF; ">return</span>&nbsp;valid;&nbsp;<br />}&nbsp;<br />}</div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><div><span style="font-size: 14px; ">该模式是前面模式的扩展；将某个值发布以在程序内的其他地方使用，但是与一次性事件的发布不同，这是一系列独立事件。这个模式要求被发布的值是有效不可变的 &#8212;&#8212; 即值的状态在发布后不会更改。使用该值的代码需要清楚该值可能随时发生变化。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">模式 #4：&#8220;volatile bean&#8221; 模式</strong><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　volatile bean 模式适用于将 JavaBeans 作为&#8220;荣誉结构&#8221;使用的框架。在 volatile bean 模式中，JavaBean 被用作一组具有 getter 和/或 setter 方法 的独立属性的容器。volatile bean 模式的基本原理是：很多框架为易变数据的持有者（例如 HttpSession）提供了容器，但是放入这些容器中的对象必须是线程安全的。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　在 volatile bean 模式中，JavaBean 的所有数据成员都是 volatile 类型的，并且 getter 和 setter 方法必须非常普通 &#8212;&#8212; 除了获取或设置相应的属性外，不能包含任何逻辑。此外，对于对象引用的数据成员，引用的对象必须是有效不可变的。（这将禁止具有数组值的属性，因为当数组引用被声明为 volatile 时，只有引用而不是数组本身具有 volatile 语义）。对于任何 volatile 变量，不变式或约束都不能包含 JavaBean 属性。清单 5 中的示例展示了遵守 volatile bean 模式的 JavaBean：</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">清单 5. 遵守 volatile bean 模式的 Person 对象</strong></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><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 />-->@ThreadSafe&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Person&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">volatile</span>&nbsp;String&nbsp;firstName;&nbsp;<br /><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">volatile</span>&nbsp;String&nbsp;lastName;&nbsp;<br /><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">volatile</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;age;&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;getFirstName()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;firstName;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;getLastName()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;lastName;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getAge()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;age;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setFirstName(String&nbsp;firstName)&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">this</span>.firstName&nbsp;=&nbsp;firstName;&nbsp;<br />}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setLastName(String&nbsp;lastName)&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">this</span>.lastName&nbsp;=&nbsp;lastName;&nbsp;<br />}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setAge(<span style="color: #0000FF; ">int</span>&nbsp;age)&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">this</span>.age&nbsp;=&nbsp;age;&nbsp;<br />}&nbsp;<br />}</div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><div><strong style="font-size: 14px; ">volatile 的高级模式</strong><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　前面几节介绍的模式涵盖了大部分的基本用例，在这些模式中使用 volatile 非常有用并且简单。这一节将介绍一种更加高级的模式，在该模式中，volatile 将提供性能或可伸缩性优势。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　volatile 应用的的高级模式非常脆弱。因此，必须对假设的条件仔细证明，并且这些模式被严格地封装了起来，因为即使非常小的更改也会损坏您的代码！同样，使用更高级的 volatile 用例的原因是它能够提升性能，确保在开始应用高级模式之前，真正确定需要实现这种性能获益。需要对这些模式进行权衡，放弃可读性或可维护性来换取可能的性能收益 &#8212;&#8212; 如果您不需要提升性能（或者不能够通过一个严格的测试程序证明您需要它），那么这很可能是一次糟糕的交易，因为您很可能会得不偿失，换来的东西要比放弃的东西价值更低。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">模式 #5：开销较低的读－写锁策略</strong><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　目前为止，您应该了解了 volatile 的功能还不足以实现计数器。因为 ++x 实际上是三种操作（读、添加、存储）的简单组合，如果多个线程凑巧试图同时对 volatile 计数器执行增量操作，那么它的更新值有可能会丢失。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　然而，如果读操作远远超过写操作，您可以结合使用内部锁和 volatile 变量来减少公共代码路径的开销。清单 6 中显示的线程安全的计数器使用 synchronized 确保增量操作是原子的，并使用 volatile 保证当前结果的可见性。如果更新不频繁的话，该方法可实现更好的性能，因为读路径的开销仅仅涉及 volatile 读操作，这通常要优于一个无竞争的锁获取的开销。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; "><strong>清单 6. 结合使用 volatile 和 synchronized 实现 &#8220;开销较低的读－写锁&#8221;</strong></strong></div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->@ThreadSafe&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;CheesyCounter&nbsp;{&nbsp;<br /><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Employs&nbsp;the&nbsp;cheap&nbsp;read-write&nbsp;lock&nbsp;trick&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;All&nbsp;mutative&nbsp;operations&nbsp;MUST&nbsp;be&nbsp;done&nbsp;with&nbsp;the&nbsp;'this'&nbsp;lock&nbsp;held&nbsp;</span><span style="color: #008000; "><br /></span>@GuardedBy("this")&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;volatileint&nbsp;value;&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getValue()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;value;&nbsp;}&nbsp;<br /><span style="color: #0000FF; ">public</span>&nbsp;synchronizedint&nbsp;increment()&nbsp;{&nbsp;<br /><span style="color: #0000FF; ">return</span>&nbsp;value++;&nbsp;<br />}&nbsp;<br />}</div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span><div><span style="font-size: 14px; ">之所以将这种技术称之为 &#8220;开销较低的读－写锁&#8221; 是因为您使用了不同的同步机制进行读写操作。因为本例中的写操作违反了使用 volatile 的第一个条件，因此不能使用 volatile 安全地实现计数器 &#8212;&#8212; 您必须使用锁。然而，您可以在读操作中使用 volatile 确保当前值的</span><em style="font-size: 14px; ">可见性</em><span style="font-size: 14px; ">，因此可以使用锁进行所有变化的操作，使用 volatile 进行只读操作。其中，锁一次只允许一个线程访问值，volatile 允许多个线程执行读操作，因此当使用 volatile 保证读代码路径时，要比使用锁执行全部代码路径获得更高的共享度 &#8212;&#8212; 就像读－写操作一样。然而，要随时牢记这种模式的弱点：如果超越了该模式的最基本应用，结合这两个竞争的同步机制将变得非常困难。</span><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　</span><strong style="font-size: 14px; ">结束语</strong><div style="height: 14px; line-height: 14px; font-size: 12px; overflow-x: hidden; overflow-y: hidden; "></div><span style="font-size: 14px; ">　　与锁相比，Volatile 变量是一种非常简单但同时又非常脆弱的同步机制，它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循 volatile 的使用条件 &#8212;&#8212; 即变量真正独立于其他变量和自己以前的值 &#8212;&#8212; 在某些情况下可以使用 volatile 代替 synchronized 来简化代码。然而，使用 volatile 的代码往往比使用锁的代码更加容易出错。本文介绍的模式涵盖了可以使用 volatile 代替 synchronized 的最常见的一些用例。遵循这些模式（注意使用时不要超过各自的限制）可以帮助您安全地实现大多数用例，使用 volatile 变量获得更佳性能。</span></div><div><span style="font-size: 14px; "><br /></span></div><span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; background-color: #ffffff; "><br /></span></div><img src ="http://www.blogjava.net/RoyPayne/aggbug/367989.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2012-01-06 10:44 <a href="http://www.blogjava.net/RoyPayne/archive/2012/01/06/367989.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 的 Thread.sleep() 和 Thread.wait() 的区别</title><link>http://www.blogjava.net/RoyPayne/archive/2012/01/05/367910.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Thu, 05 Jan 2012 06:32:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2012/01/05/367910.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/367910.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2012/01/05/367910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/367910.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/367910.html</trackback:ping><description><![CDATA[<div><pre style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; white-space: pre-wrap; font-size: 14px; line-height: 22px; background-color: #ffffff; ">两者的区别有：<br /> 1、最主要是sleep方法没有释放锁，而wait方法释放了锁，使得其他<a href="http://wenwen.soso.com/z/Search.e?sp=S%E7%BA%BF%E7%A8%8B&amp;ch=w.search.yjjlink&amp;cid=w.search.yjjlink" target="_blank" style="color: #005599; text-decoration: none; border-bottom-width: 1px; border-bottom-style: dotted; border-bottom-color: #005599; ">线程</a>可以使用<a href="http://wenwen.soso.com/z/Search.e?sp=S%E5%90%8C%E6%AD%A5%E6%8E%A7%E5%88%B6&amp;ch=w.search.yjjlink&amp;cid=w.search.yjjlink" target="_blank" style="color: #005599; text-decoration: none; border-bottom-width: 1px; border-bottom-style: dotted; border-bottom-color: #005599; ">同步控制</a>块或者方法。 2、这两个方法来自不同的类分别是Thread和Object<br /><br /> 3、wait，notify和notifyAll只能在同步控制方法或者同步控制块里面使用，而sleep可以在<br />    任何地方使用<br />   synchronized(x){<br />      x.notify()<br />     //或者wait()<br />   }<br />  4、sleep必须捕获异常，而wait，notify和notifyAll不需要捕获异常</pre></div><img src ="http://www.blogjava.net/RoyPayne/aggbug/367910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2012-01-05 14:32 <a href="http://www.blogjava.net/RoyPayne/archive/2012/01/05/367910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lock和Synchronized</title><link>http://www.blogjava.net/RoyPayne/archive/2011/12/28/367436.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Wed, 28 Dec 2011 09:22:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2011/12/28/367436.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/367436.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2011/12/28/367436.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/367436.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/367436.html</trackback:ping><description><![CDATA[&nbsp; &nbsp;java锁机制有两种实现方式：jdk1.4 通过synchronized的方式实现，jdk1.5加入java.util.concurrent.locks包下的各种lock<br /><br />1.代码层的区别。<br />synchronized 类似面向对象 修饰 类，方法，对象。<br />lock不作为修饰，类似面向过程，在方法中需要锁的时候lock，在结束的时候unlock。（一般在finally块里）<br /><br />2.性能<br />并发高，lock有优势。低并发 synchronized 有优势。<br /><br />3.实现机制<br /><br /><div>synchronized 对象加锁</div><img src ="http://www.blogjava.net/RoyPayne/aggbug/367436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2011-12-28 17:22 <a href="http://www.blogjava.net/RoyPayne/archive/2011/12/28/367436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 里面volatile什么意思啊</title><link>http://www.blogjava.net/RoyPayne/archive/2011/12/28/367405.html</link><dc:creator>RoyPayne</dc:creator><author>RoyPayne</author><pubDate>Wed, 28 Dec 2011 05:58:00 GMT</pubDate><guid>http://www.blogjava.net/RoyPayne/archive/2011/12/28/367405.html</guid><wfw:comment>http://www.blogjava.net/RoyPayne/comments/367405.html</wfw:comment><comments>http://www.blogjava.net/RoyPayne/archive/2011/12/28/367405.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RoyPayne/comments/commentRss/367405.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RoyPayne/services/trackbacks/367405.html</trackback:ping><description><![CDATA[<pre id="best-answer-content"  mb10"="" style="margin-top: 0px; margin-bottom: 10px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Arial; white-space: pre-wrap; word-wrap: break-word; zoom: 1; line-height: 22px; background-color: #fffcf6; "><span style="font-size: 10pt; ">    </span><span style="font-size: 10pt; ">  Volatile修饰的成员变量在每次被线程访问时，都强迫从共享内存中重读该成员变量的值。而且，当成员变量发生变化时，强迫线程将变化值回写到共享内存。这样在任何时刻，两</span><br /><br /><span style="font-size: 10pt; ">个不同的线程总是看到某个成员变量的同一个值。  Java语言规范中指出：为了获得最佳速度，允许线程保存共享成员变量的私有拷贝，而且只当线程进入或者离开同步代码块时才与</span><br /><br /><span style="font-size: 10pt; ">共享成员变量的原始值对比。  这样当多个线程同时与某个对象交互时，就必须要注意到要让线程及时的得到共享成员变量的变化。  而volatile关键字就是提示VM：对于这个成员变量</span><br /><br /><span style="font-size: 10pt; ">不能保存它的私有拷贝，而应直接与共享成员变量交互。  使用建议：在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中，或者为常量</span><br /><br /><span style="font-size: 10pt; ">时，不必使用。  由于使用volatile屏蔽掉了VM中必要的代码优化，所以在效率上比较低，因此一定在必要时才使用此关键字。    就跟C中的一样 禁止编译器进行优化~~~~</span></pre><img src ="http://www.blogjava.net/RoyPayne/aggbug/367405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RoyPayne/" target="_blank">RoyPayne</a> 2011-12-28 13:58 <a href="http://www.blogjava.net/RoyPayne/archive/2011/12/28/367405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>