??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美日本一区,亚洲精品视频在线观看网站,黄网站app在线观看下载视频大全官网 http://www.aygfsteel.com/jesson2005/articles/200958.html张金?/dc:creator>张金?/author>Fri, 16 May 2008 09:07:00 GMThttp://www.aygfsteel.com/jesson2005/articles/200958.htmlhttp://www.aygfsteel.com/jesson2005/comments/200958.htmlhttp://www.aygfsteel.com/jesson2005/articles/200958.html#Feedback0http://www.aygfsteel.com/jesson2005/comments/commentRss/200958.htmlhttp://www.aygfsteel.com/jesson2005/services/trackbacks/200958.html 一个线E池qE池理?工作U程 d队列和Q务接口组?
一 U程池管理器---ThreadPoolMananger 主要负责启动 停止工作U程
  1. public class ThreadPoolManager {   
  2.   
  3.     private static int DEFAULT_POOL_SIZE = 4;   
  4.     private List<WorkThread> threadPool;   
  5.     private Queue<Task> taskQueue;   
  6.     private int poolSize;   
  7.        
  8.     public ThreadPoolManager(){   
  9.         this(DEFAULT_POOL_SIZE);   
  10.     }   
  11.        
  12.     public ThreadPoolManager(int poolSize){   
  13.         if(poolSize <= 0){   
  14.             this.poolSize = DEFAULT_POOL_SIZE;   
  15.         }else{   
  16.             this.poolSize = poolSize;   
  17.         }   
  18.            
  19.         threadPool = new ArrayList<WorkThread>(this.poolSize);   
  20.         taskQueue = new ConcurrentLinkedQueue<Task>();   
  21.            
  22.         startup();   
  23.     }   
  24.        
  25.     /**  
  26.      * 启动U程?nbsp;开始处理Q? 
  27.      */  
  28.     private void startup(){   
  29.         System.out.println("启动工作U程。。?);   
  30.         synchronized(taskQueue){   
  31.             for(int i = 0; i < DEFAULT_POOL_SIZE; i++){   
  32.                 WorkThread workThread = new WorkThread(taskQueue);   
  33.                 threadPool.add( workThread );   
  34.                 workThread.start();   
  35.             }   
  36.         }   
  37.            
  38.     }   
  39.        
  40.     /**  
  41.      * 停止工作U程。工作线E不一定立卛_止,只有在线E处于运行状态时?x)立卛_? 
  42.      */  
  43.     public void shutdown(){   
  44.         System.out.println("停止工作U程.");   
  45.         synchronized(taskQueue){   
  46.             for(int i = 0; i < DEFAULT_POOL_SIZE; i++){   
  47.                 threadPool.get(i).shutdown();   
  48.             }   
  49.         }   
  50.     }   
  51.        
  52.     /**  
  53.      * d消息到队?    
  54.      */  
  55.     public void addTask(Task task){   
  56.         synchronized(taskQueue){   
  57.             taskQueue.add(task);   
  58.             taskQueue.notifyAll();     
  59.         }   
  60.     }   
  61.   
  62. }  

?工作U程---WorkerThread ֐思义 它本w就是一个线E,而且是专门用来工作的Q工作线E的主要d是从d队列中取ZQ?然后执行d

  • /**  
  •  * 工作U程  
  •  * @author XuLiangYong  
  •  * Jul 20, 2007 3:47:52 PM  
  •  */  
  • public class WorkThread extends Thread{   
  •     private boolean shutdown = false;   
  •     private Queue<Task> queue;   
  •        
  •     public WorkThread(Queue<Task> queue){   
  •         this.queue = queue;   
  •     }   
  •        
  •     public void run(){   
  •         while(!shutdown){   
  •             synchronized(queue){ //获得对象?nbsp;止其他U程讉K   
  •                 if(!queue.isEmpty()){   
  •                     //处理d    
  •                     Task task = queue.poll();   
  •                     task.execute();   
  •                 }else{   
  •                     try {   
  •                         queue.wait(); //释放?nbsp;U程处于阻赛状?nbsp;{待notify唤醒   
  •                     } catch (InterruptedException e) {   
  •                     }   
  •                 }   
  •             }   
  •         }//end while   
  •     }   
  •        
  •     /**  
  •      * 调用该方法后不一定会(x)立即l束U程Q?nbsp;只有在线E处于运行状态且处理完当前Q务后才结? 
  •      */  
  •     public void shutdown(){   
  •         shutdown = true;   
  •     }   
  • }  
  •  

    ?d队列---TaskQueue FIFO数据l构 在出对入队的时候要锁定对象避免两个U程重复处理某Q?
    在这里我采用的是java提供的ConcurrentLinkedQueue队列Q这是一个用链表实现的队 可无限的扩大Q具体用法请看doc
    用到队列的地方主要有两个 addTask(Task task) ?Task task = queue.poll();


    ?d接口---Task d接口只有一个方?executeQ)(j)Q用者只需实现q个接口可以了(jin)

  • public interface Task {   
  •     void execute();   
  • }


  • 用法Q?/p>

  • public class TestThreadPoolManager extends TestCase {   
  •        
  •     public void test(){   
  •         ThreadPoolManager pool = new ThreadPoolManager();   
  •         for(int i = 0; i < 100; i++){   
  •             pool.addTask(new SimpleTask(new MyManager(), i)); //SimpleTask实现?jin)Task接口   
  •         }   
  •         pool.shutdown();   
  •     }   
  •        
  • 可以看出用户的用非常简?
    在jdk5?java提供?jin)线E池
    有一Ҏ(gu)?千万不要在servlet中调用线E池 因ؓ(f)servlet本来是一个线E池




    ]]>
    U程池的介绍?qing)简单实?/title><link>http://www.aygfsteel.com/jesson2005/articles/96934.html</link><dc:creator>张金?/dc:creator><author>张金?/author><pubDate>Wed, 31 Jan 2007 05:57:00 GMT</pubDate><guid>http://www.aygfsteel.com/jesson2005/articles/96934.html</guid><wfw:comment>http://www.aygfsteel.com/jesson2005/comments/96934.html</wfw:comment><comments>http://www.aygfsteel.com/jesson2005/articles/96934.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jesson2005/comments/commentRss/96934.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jesson2005/services/trackbacks/96934.html</trackback:ping><description><![CDATA[ <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="100%"> <h1 align="center">U程池的介绍?qing)简单实?/h1> <img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" /> </td> <td class="no-print" width="192"> </td> </tr> </tbody> </table> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="10"> <img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /> </td> <td width="100%"> <p>服务器程序利用线E技术响应客戯求已l司I?可能(zhn)认样做效率已经很高Q但(zhn)有没有惌优化一下用线E的Ҏ(gu)。该文章向(zhn)介l服务器E序如何利用U程池来优化性能q提供一个简单的U程池实现?/p> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <p> <a name="1"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">U程池的技术背?/font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p>在面向对象编E中Q创建和销毁对象是很费旉的,因ؓ(f)创徏一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后q行垃圾回收。所以提高服务程序效率的一个手D就是尽可能减少创徏和销毁对象的ơ数Q特别是一些很耗资源的对象创徏和销毁。如何利用已有对象来服务是一个需要解决的关键问题Q其实这是一?池化资源"技术生的原因。比如大家所熟?zhn)的数据库q接池正是遵循这一思想而生的Q本文将介绍的线E池技术同L(fng)合这一思想?/p> <p>目前Q一些著名的大公叔R特别看好q项技术,q早已经在他们的产品中应用该技术。比如IBM的WebSphereQIONA的Orbix 2000在SUN?Jini中,Microsoft的MTSQMicrosoft Transaction Server 2.0Q,COM+{?/p> <p>现在(zhn)是否也惛_服务器程序应用该Ҏ(gu)?</p> <br /> <p> <a name="2"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">U程池技术如何提高服务器E序的性能</font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p>我所提到服务器程序是指能够接受客戯求ƈ能处理请求的E序Q而不只是指那些接受网l客戯求的|络服务器程序?/p> <p>多线E技术主要解军_理器单元内多个线E执行的问题Q它可以显著减少处理器单元的闲置旉Q增加处理器单元的吞吐能力。但如果对多U程应用不当Q会(x)增加对单个Q务的处理旉。可以D一个简单的例子Q?/p> <p>假设在一台服务器完成一Q务的旉为T</p> <pre> T1 创徏U程的时? T2 在线E中执行d的时_(d)包括U程间同步所需旉 T3 U程销毁的旉 </pre> <p>昄T Q?T1QT2QT3。注意这是一个极度简化的假设?/p> <p>可以看出T1,T3是多U程本n的带来的开销Q我们(f)望减T1,T3所用的旉Q从而减T的时间。但一些线E的使用者ƈ没有注意到这一点,所以在E序中频J的创徏或销毁线E,q导致T1和T3在T中占有相当比例。显然这是突Z(jin)U程的弱点(T1QT3Q,而不是优点(q发性)(j)?/p> <p>U程池技术正是关注如何羃短或调整T1,T3旉的技术,从而提高服务器E序性能的。它把T1QT3分别安排在服务器E序的启动和l束的时间段或者一些空闲的旉D,q样在服务器E序处理客户hӞ不会(x)有T1QT3的开销?jin)?/p> <p>U程池不仅调整T1,T3产生的时间段Q而且它还显著减少?jin)创建线E的数目。在看一个例子:(x)</p> <p>假设一个服务器一天要处理50000个请求,q且每个h需要一个单独的U程完成。我们比较利用线E池技术和不利于线E池技术的服务器处理这些请求时所产生的线EL。在U程池中Q线E数一般是固定的,所以生线EL不会(x)过U程池中U程的数目或者上限(以下U线E池寸Q,而如果服务器不利用线E池来处理这些请求则U程L?0000。一般线E池寸是远于50000。所以利用线E池的服务器E序不会(x)Z(jin)创徏50000而在处理h时浪Ҏ(gu)_(d)从而提高效率?/p> <p>q些都是假设Q不能充分说明问题,下面我将讨论U程池的单实现ƈ对该E序q行Ҏ(gu)试Q以说明U程技术优点及(qing)应用领域?/p> <br /> <br /> <p> <a name="3"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">U程池的单实现及(qing)Ҏ(gu)试</font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p>一般一个简单线E池臛_包含下列l成部分?/p> <ol> <li>U程池管理器QThreadPoolManagerQ?用于创徏q管理线E池 </li> <li>工作U程QWorkThreadQ? U程池中U程 </li> <li>d接口QTaskQ?每个d必须实现的接口,以供工作U程调度d的执行? </li> <li>d队列:用于存放没有处理的Q务。提供一U缓冲机制?</li> </ol> <p>U程池管理器臛_有下列功能:(x)创徏U程池,销毁线E池Q添加新d创徏U程池的部分代码如下Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"> ? //create threads synchronized(workThreadVector) { for(int j = 0; j < i; j++) { threadNum++; WorkThread workThread = new WorkThread(taskVector, threadNum); workThreadVector.addElement(workThread); } } ? </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>注意同步workThreadVectorq没有降低效率,相反提高?sh)(jin)效?请参考Brian Goetz的文章?销毁线E池的部分代码如下:(x)</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"> ? while(!workThreadVector.isEmpty()) { if(debugLevel > 2) System.out.println("stop:"+(i)); i++; try { WorkThread workThread = (WorkThread)workThreadVector.remove(0); workThread.closeThread(); continue; } catch(Exception exception) { if(debugLevel > 2) exception.printStackTrace(); } break; } ? </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>dCQ务的部分代码如下Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console"> ? synchronized(taskVector) { taskVector.addElement(taskObj); taskVector.notifyAll(); } ? </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>工作U程是一个可以@环执行Q务的U程Q在没有d时将{待。由于代码比较多在此不罗?</p> <p>d接口是ؓ(f)所有Q务提供统一的接口,以便工作U程处理。Q务接口主要规定了(jin)d的入口,d执行完后的收ַ作,d的执行状态等。在文章l尾有相关代码的下蝲?/p> <p>以上所描述的线E池l构很简单,一些复杂的U程池结构将不再此讨论?/p> <p>在下载代码中有测试驱动程序(TestThreadPoolQ,我利用这个测试程序的输出数据l计Z列测试结果。测试有两个参数要设|:(x)</p> <ol> <li>U程池中U程敎ͼ即线E池寸? </li> <li>要完成的d数?</li> </ol> <p>分别一个参数固定,另一个参数变动以考察两个参数所产生的不同结果。所用测试机器分别ؓ(f)普通PC机(Win2000 JDK1.3.1Q和SUN服务?Solaris Unix JDK1.3.1)Q机器配|在此不便指明?/p> <p> <a name="N100B0"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">?:试数据?qing)对应结?/font> </strong> </span> </a> </p> <p> </p> <table width="80%" border="1"> <tbody> <tr bgcolor="#c0c0c0"> <td>U程池尺?/td> <td>d?/td> <td>没有应用U程池所用的旉Q单?毫秒QOS:winQ?/td> <td>应用U程池所用的旉Q单?毫秒QOS:winQ?/td> <td>没有应用U程池所用的旉Q单?毫秒QOS:SolarisQ?/td> <td>应用U程池所用的旉Q单?毫秒QOS:SolarisQ?/td> </tr> <tr> <td>1</td> <td>5000</td> <td>3896</td> <td>130</td> <td>6513</td> <td>327</td> </tr> <tr> <td>2</td> <td>5000</td> <td>3455</td> <td>151</td> <td>6221</td> <td>659</td> </tr> <tr> <td>4</td> <td>5000</td> <td>3425</td> <td>120</td> <td>5448</td> <td>433</td> </tr> <tr> <td>8</td> <td>5000</td> <td>3475</td> <td>160</td> <td>5769</td> <td>1478</td> </tr> <tr> <td>16</td> <td>5000</td> <td>3505</td> <td>211</td> <td>5785</td> <td>1970</td> </tr> <tr> <td>32</td> <td>5000</td> <td>3455</td> <td>251</td> <td>6403</td> <td>875</td> </tr> <tr> <td>64</td> <td>5000</td> <td>3595</td> <td>501</td> <td>5182</td> <td>1103</td> </tr> <tr> <td>128</td> <td>5000</td> <td>3515</td> <td>881</td> <td>5154</td> <td>405</td> </tr> <tr> <td>256</td> <td>5000</td> <td>3495</td> <td>3104</td> <td>5502</td> <td>1589</td> </tr> <tr> <td>512</td> <td>5000</td> <td>3425</td> <td>5488</td> <td>5667</td> <td>1262</td> </tr> <tr> <td>16</td> <td>1</td> <td>20</td> <td>0</td> <td>22</td> <td>3</td> </tr> <tr> <td>16</td> <td>2</td> <td>20</td> <td>20</td> <td>21</td> <td>13</td> </tr> <tr> <td>16</td> <td>4</td> <td>20</td> <td>10</td> <td>27</td> <td>10</td> </tr> <tr> <td>16</td> <td>8</td> <td>20</td> <td>20</td> <td>22</td> <td>24</td> </tr> <tr> <td>16</td> <td>16</td> <td>30</td> <td>20</td> <td>29</td> <td>48</td> </tr> <tr> <td>16</td> <td>32</td> <td>40</td> <td>20</td> <td>46</td> <td>108</td> </tr> <tr> <td>16</td> <td>64</td> <td>60</td> <td>20</td> <td>72</td> <td>199</td> </tr> <tr> <td>16</td> <td>128</td> <td>110</td> <td>20</td> <td>148</td> <td>335</td> </tr> <tr> <td>16</td> <td>256</td> <td>201</td> <td>20</td> <td>252</td> <td>132</td> </tr> <tr> <td>16</td> <td>512</td> <td>411</td> <td>40</td> <td>522</td> <td>382</td> </tr> <tr> <td>16</td> <td>1024</td> <td>811</td> <td>71</td> <td>1233</td> <td>610</td> </tr> <tr> <td>16</td> <td>2048</td> <td>1552</td> <td>80</td> <td>2045</td> <td>135</td> </tr> <tr> <td>16</td> <td>4096</td> <td>2874</td> <td>250</td> <td>4828</td> <td>787</td> </tr> </tbody> </table> <br /> <a name="N102B9"> <b>?.U程池的寸的对服务器程序的性能影响</b> </a> <br /> <img height="372" alt="?.U程池的寸的对服务器程序的性能影响" src="http://www-128.ibm.com/developerworks/cn/java/l-threadPool/ThreadPoolTest1.gif" width="596" /> <br /> <p>Ҏ(gu)以上l计数据可得Z图:(x)</p> <br /> <a name="N102CB"> <b>?.d数对服务器程序的冲击 </b> </a> <br /> <img height="373" alt="?.d数对服务器程序的冲击" src="http://www-128.ibm.com/developerworks/cn/java/l-threadPool/ThreadPoolTest2.gif" width="594" /> <br /> <p>数据分析如下Q?/p> <p>?是改变线E池寸Ҏ(gu)务器性能的媄(jing)响,在该试q程中,服务器的要完成的d数固定ؓ(f)?000。从?中可以看出合理配|线E池寸对于大量d处理的效率有非常明显的提高,但是一旦尺寔R择不合理(q大或过)(j)׃(x)严重降低影响服务器性能。理Z"q小"出CQ务不能及(qing)时处理的情况,但在图表中显C出某些尺寸的U程池表现很好,q是因ؓ(f)试驱动中有很多U程同步开销Q且q个开销相对于完成单个Q务的旉是不能忽略的?q大"则会(x)出现U程间同步开销太大的问题,而且在线E间切换很耗CPU旉Q在图表昄的很清楚。可见Q何一个好技术,如果滥用都会(x)造成N性后果?/p> <p>?是用不同数量的Q务来冲击服务器程序,在该试q程中,服务器线E池寸固定?6。可以看出线E池在处理少量Q务时的优势不明显。所以线E池技术有一定的适应范围Q关于适用范围在后面讨论。但对于大量的Q务的处理Q线E池的优势表现非常卓,服务器程序处理请求的旉虽然有L动,但是其^均值相对小多了(jin)?/p> <p>值得注意的是试Ҏ(gu)中,l计d的完成时间没有包含了(jin)创徏U程池的旉。在实际U程池工作时Q即利用U程池处理Q务时Q创建线E池的时间是不必计算在内的?/p> <p>׃试驱动E序有很多同步代码,特别是等待线E执行完毕的同步Q代码中为sleepToWait(long l)Ҏ(gu)的调用)(j)Q这些代码降低了(jin)代码执行效率Q这是测试驱动一个缺点,但这个测试驱动可以说明线E池相对于简单用线E的优势?/p> <br /> <br /> <p> <a name="4"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">关于高U程池的探讨</font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p>单线E池存在一些问题,比如如果有大量的客户要求服务器ؓ(f)其服务,但由于线E池的工作线E是有限的,服务器只能ؓ(f)部分客户服务Q其它客h交的dQ只能在d队列中等待处理。一些系l设计h员可能会(x)不满q种状况Q因Z们对服务器程序的响应旉要求比较严格Q所以在pȝ设计时可能会(x)怀疑线E池技术的可行性,但是U程池有相应的解x(chng)案。调整优化线E池寸是高U线E池要解决的一个问题。主要有下列解决Ҏ(gu)Q?/p> <p> <a name="N102F2"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">Ҏ(gu)一Q动态增加工作线E?/font> </strong> </span> </a> </p> <p> <strong> <font face="Arial"> </font> </strong> </p> <p>在一些高U线E池中一般提供一个可以动态改变的工作U程数目的功能,以适应H发性的h。一旦请求变了(jin)逐步减少U程池中工作U程的数目。当然线E增加可以采用一U超前方式,x(chng)量增加一批工作线E,而不是来一个请求才建立创徏一个线E。批量创建是更加有效的方式。该Ҏ(gu)q有应该限制U程池中工作U程数目的上限和下限。否则这U灵zȝ方式也就变成一U错误的方式或者灾难,因ؓ(f)频繁的创建线E或者短旉内生大量的U程会(x)背离使用U程池原始初?-减少创徏U程的次数?/p> <p>举例QJini中的TaskManagerQ就是一个精巧线E池理器,它是动态增加工作线E的。SQL Server采用单进E?Single Process)多线E?Multi-Thread)的系l结构,1024个数量的U程池,动态线E分配,理论上限32767?/p> <p> <a name="N10300"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">Ҏ(gu)二:(x)优化工作U程数目</font> </strong> </span> </a> </p> <p> <strong> <font face="Arial"> </font> </strong> </p> <p>如果不想在线E池应用复杂的策略来保证工作U程数满_用的要求Q你pҎ(gu)l计学的原理来统计客L(fng)h数目Q比如高峰时D^均一U钟内有多少d要求处理QƈҎ(gu)pȝ的承受能力及(qing)客户的忍受能力来q估计一个合理的U程池尺寸。线E池的尺寸确实很隄定,所以有时干脆用l验倹{?/p> <p>举例Q在MTS中线E池的尺寸固定ؓ(f)100?/p> <p> <a name="N1030E"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">Ҏ(gu)三:(x)一个服务器提供多个U程?/font> </strong> </span> </a> </p> <p> <strong> <font face="Arial"> </font> </strong> </p> <p>在一些复杂的pȝl构?x)采用这个方案。这样可以根据不同Q务或者Q务优先来采用不同线E池处理?/p> <p>举例QCOM+用到?jin)多个线E池?/p> <p>q三U方案各有优~点。在不同应用中可能采用不同的Ҏ(gu)或者干脆组合这三种Ҏ(gu)来解军_际问题?/p> <br /> <br /> <p> <a name="5"> <span id="wmqeeuq" class="atitle"> <font face="Arial" size="4">U程池技术适用范围?qing)应注意的问?/font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p>下面是我ȝ的一些线E池应用范围,可能是不全面的?/p> <p>U程池的应用范围Q?/p> <ol> <li>需要大量的U程来完成Q务,且完成Q务的旉比较短?WEB服务器完成网请求这L(fng)dQ用线E池技术是非常合适的。因为单个Q务小Q而Q务数量巨大,你可以想象一个热门网站的点击ơ数?但对于长旉的Q务,比如一个Telnetq接hQ线E池的优点就不明显了(jin)。因为Telnet?x)话旉比线E的创徏旉大多?jin)? </li> <li>Ҏ(gu)能要求苛刻的应用,比如要求服务器迅速相应客戯求? </li> <li>接受H发性的大量hQ但不至于服务器因此生大量线E的应用。突发性大量客戯求,在没有线E池情况下,生大量线E,虽然理论上大部分操作pȝU程数目最大g是问题,短时间内产生大量U程可能使内存到达极限,q出?OutOfMemory"的错误?</li> </ol> <p> <font face="Arial" size="4"> </font> </p> <p>本文只是单介l线E池技术。可以看出线E池技术对于服务器E序的性能改善是显著的。线E池技术在服务器领域有着q泛的应用前景。希望这Ҏ(gu)术能够应用到(zhn)的多线E服务程序中?/p> </td> </tr> </tbody> </table> <img src ="http://www.aygfsteel.com/jesson2005/aggbug/96934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jesson2005/" target="_blank">张金?/a> 2007-01-31 13:57 <a href="http://www.aygfsteel.com/jesson2005/articles/96934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA后台E序设计?qing)UTIL.CONCURRENT包的应用http://www.aygfsteel.com/jesson2005/articles/96927.html张金?/dc:creator>张金?/author>Wed, 31 Jan 2007 05:52:00 GMThttp://www.aygfsteel.com/jesson2005/articles/96927.htmlhttp://www.aygfsteel.com/jesson2005/comments/96927.htmlhttp://www.aygfsteel.com/jesson2005/articles/96927.html#Feedback0http://www.aygfsteel.com/jesson2005/comments/commentRss/96927.htmlhttp://www.aygfsteel.com/jesson2005/services/trackbacks/96927.htmlJAVA后台E序设计?qing)UTIL.CONCURRENT包的应用
    JAVA后台E序设计?qing)UTIL.CONCURRENT包的应用

    ??br />
    摘要 : 在很多Y仉目中QJAVA语言常常被用来开发后台服务程序。线E池技术是提高q类E序性能的一个重要手Dc(din)在实践中,该技术已l被q泛的用。本文首?对设计后台服务程序通常需要考虑的问题进行了(jin)基本的论qͼ随后介绍?jin)JAVAU程池的原理、用和其他一些相关问题,最后对功能强大的JAVA开放源码线 E池包util.concurrent 在实际编E中的应用进行了(jin)详细介绍?br />关键? JAVAQ线E池Q后台服务程序;util.concurrent


    1 引言
    在Y仉目开发中Q许多后台服务程序的处理动作程都具有一个相同点Q就是:(x)接受客户端发来的hQ对hq行一些相关的处理Q最后将处理l果q回l客?端。这些请求的来源和方式可能会(x)各不相同Q但是它们常帔R有一个共同点Q数量巨大,处理旉短。这cL务器在实际应用中h较大的普遍性,如web服务 器,短信服务器,DNS服务器等{。因此,研究如何提高此类后台E序的性能Q如何保证服务器的稳定性以?qing)安全性都h重要的实用h(hun)倹{?br />
    2 后台服务E序设计
    2.1 关于设计原型
    构徏服务器应用程序的一个简单的模型是:(x)启动一个无限@环,循环里放一个监听线E监听某个地址端口。每当一个请求到辑ְ创徏一个新U程Q然后新U程求服务,监听U程q回l箋(hu)监听?br />单D例如下:(x)
    import java.net.*;
    public class MyServer extends Thread{
    public void run(){
    try{
    ServerSocket server=null;
    Socket clientconnection=null;
    server = new ServerSocket(8008);//监听某地址端口?br />while(true){q入无限循环
    clientconnection =server.accept();//收取h
    new ServeRequest(clientconnection).start();//启动一个新服务U程q行服务
    …?br />}
    }catch(Exception e){
    System.err.println("Unable to start serve listen:"+e.getMessage());
    e.printStackTrace();
    }
    }
    }
    实际上,q只是个单的原型Q如果试N|以q种方式q行的服务器应用E序Q那么这U方法的严重不很明显?br />首先Qؓ(f)每个h创徏一个新U程的开销很大Qؓ(f)每个h创徏新线E的服务器在创徏和销毁线E上p的时间和消耗的pȝ资源, 往往有时候要比花在处理实际的用户h的时间和资源更多。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后q行垃圾回收。所以提 高服务程序效率的一个手D就是尽可能减少创徏和销毁对象的ơ数。这L(fng)合看来,pȝ的性能瓉在于线E的创徏开销?br />其次Q除?jin)创建和销毁线E的开销之外Q活动的U程也消耗系l资源。在一?JVM 里创建太多的U程可能?x)导致系l由于过度消耗内存而用完内存或“切换过度”。ؓ(f)?jin)防止资源不I服务器应用程序需要一些办法来限制Ml定时刻q行的处?U程数目Q以防止服务器被“压歠Z的情况发生。所以在设计后台E序的时候,一般需要提前根据服务器的内存、CPU{硬件情况设定一个线E数量的上限倹{?br />如果创徏和销毁线E的旉相对于服务时间占用的比例较大Q那末假讑֜一个较短的旉内有成千上万的请求到达,惌一下,服务器的旉和资源将?x)大量的花?创徏和销毁线E上Q而真正用于处理请求的旉却相对较?yu),q种情况下,服务器性能瓉在于创建和销毁线E的旉。按照这个模型写一个简单的E序试一?卛_看出Q由于篇q关p,此处略。如果把Q服务时?创徏和销毁线E的旉Q作量服务器性能的一个参敎ͼ那末q个比D大,服务器的性能p高?br />应此Q解x(chng)c问题的实质是量减少创徏和销毁线E的旉Q把服务器的资源可能多地用到处理请求上来,从而发挥多U程的优点(q发Q,避免多线E的~点Q创建和销毁的时空开销Q?br />U程池ؓ(f)U程生命周期开销问题和资源不问题提供了(jin)解决Ҏ(gu)。通过对多个Q务重用线E,U程创徏的开销被分摊到?jin)多个Q务上。其好处是,因ؓ(f)在请求到达时 U程已经存在Q所以无意中也消除了(jin)U程创徏所带来的gq。这P可以立即ؓ(f)h服务Q应用E序响应更快。而且Q通过适当地调整线E池中的U程数目Q也 是当请求的数目过某个阈值时Q就强制其它M新到的请求一直等待,直到获得一个线E来处理为止Q从而可以防止资源不?br />
    3    JAVAU程池原?br />3.1 原理以及(qing)实现
    在实践中Q关于线E池的实现常常有不同的方法,但是它们的基本思\大都是相似的Q服务器预先存放一定数目的“热”的U程Qƈ发程序需要用线E的时候,?服务器取用一条已l创建好的线E(如果U程池ؓ(f)I则{待Q,使用该线E对h服务Q用结束后Q该U程q不删除Q而是q回U程池中Q以备复用,q样可以?免对每一个请求都生成和删除线E的昂贵操作?br />一个比较简单的U程池至应包含U程池管理器、工作线E、Q务队列、Q务接口等部分。其中线E池理器(ThreadPool ManagerQ的作用是创建、销毁ƈ理U程池,工作线E放入线E池中;工作U程是一个可以@环执行Q务的U程Q在没有d时进行等待;d队列的作 用是提供一U缓冲机Ӟ没有处理的d攑֜d队列中;d接口是每个Q务必d现的接口Q主要用来规定Q务的入口、Q务执行完后的收尾工作、Q务的?行状态等Q工作线E通过该接口调度Q务的执行。下面的代码实现?jin)创Z个线E池Q?br />public class ThreadPool
    {
    private Stack threadpool = new Stack();
    private int poolSize;
    private int currSize=0;
    public void setSize(int n)
    {
    poolSize = n;
    }
    public void run()
    {
    for(int i=0;i

    (发帖旉:2003-11-30 11:55:56)
    --- 岑心(j) J

    回复(1):

    4.2    框架与结?br />下面让我们来看看util.concurrent的框架结构。关于这个工具包概述的e文原版链接地址是http: //gee.cs.oswego.edu/dl/cpjslides/util.pdf。该工具包主要包括三大部分:(x)同步、通道和线E池执行器。第一部分 主要是用来定刉Q资源管理,其他的同步用途;通道则主要是为缓冲和队列服务的;U程池执行器则提供了(jin)一l完善的复杂的线E池实现?br />--主要的结构如下图所C?br />
    4.2.1 Sync
    acquire/release协议的主要接?br />- 用来定制锁,资源理Q其他的同步用?br />- 高层抽象接口
    - 没有区分不同的加锁用?br />
    实现
    -Mutex, ReentrantLock, Latch, CountDown,Semaphore, WaiterPreferenceSemaphore, FIFOSemaphore, PrioritySemaphore
    q有Q有几个单的实现Q例如ObservableSync, LayeredSync

    举例Q如果我们要在程序中获得一独占锁,可以用如下简单方式:(x)
    try {
    lock.acquire();
    try {
    action();
    }
    finally {
    lock.release();
    }
    }catchQException eQ{
    }

    E序?使用lock对象的acquire()Ҏ(gu)获得一独占锁,然后执行(zhn)的操作Q锁用完后,使用release()Ҏ(gu)释放之即可。呵呵,单吧Q想 想看Q如果?zhn)亲自撰写独占锁,大概会(x)考虑到哪些问题?如果关键的锁得不到怎末办?用v来是不是?x)复杂很多?而现在,以往的很多细节和Ҏ(gu)异常情况在这里都 无需多考虑Q?zhn)可以把_֊花在解决(zhn)的应用问题?sh)去?br />
    4.2.2 通道(Channel)
    为缓Ԍ队列{服务的L?br />
    具体实现
    LinkedQueue, BoundedLinkedQueue,BoundedBuffer, BoundedPriorityQueue, SynchronousChannel, Slot

    通道例子
    class Service { // ...
    final Channel msgQ = new LinkedQueue();
    public void serve() throws InterruptedException {
    String status = doService();
    msgQ.put(status);
    }
    public Service() { // start background thread
    Runnable logger = new Runnable() {
    public void run() {
    try {
    for(;;)
    System.out.println(msqQ.take());
    }
    catch(InterruptedException ie) {} }
    };
    new Thread(logger).start();
    }
    }
    在后台服务器中,~冲和队列都是最常用到的。试惻I如果Ҏ(gu)有远端的h不排个队列,让它们一拥而上的去争夺cpu、内存、资源,那服务器瞬间不当掉才怪。而在q里Q成熟的队列和缓冲实现已l提供,(zhn)只需要对其进行正初始化q用即可,大大~短?jin)开发时间?br />
    4.2.3执行?Executor)
    Executor是这里最重要、也是我们往往最l写E序要用到的Q下面重点对其进行介l?br />cMU程的类的主接口
    - U程?br />- 轻量U运行框?br />- 可以定制调度法

    只需要支持execute(Runnable r)
    - 同Thread.startcM

    实现
    - PooledExecutor, ThreadedExecutor, QueuedExecutor, FJTaskRunnerGroup

    PooledExecutorQ线E池执行器)(j)是个最常用到的c,以它ZQ?br />可修改得属性如下:(x)
    - d队列的类?br />- 最大线E数
    - 最线E数
    - 预热(预分?和立?分配)U程
    - 保持z跃直到工作U程l束
    -- 以后如果需要可能被一个新的代?br />- 饱和(Saturation)协议
    -- dQ丢弃,生者运行,{等

    可不要小看上面这数条属性,对这些属性的讄完全可以{同于?zhn)自己撰写的线E池的成百上千行代码。下面以W者撰写过得一个GIS服务器ؓ(f)例:(x)
    该GIS服务器是一个典型的“请求-服务”类型的服务器,遵@后端E序设计的一般框架。首先对所有的h按照先来先服务排入一个请求队列,如果瞬间到达?h过?jin)请求队列的定wQ则溢出的h转移至一个(f)旉列。如果(f)旉列也排满?jin),则对以后辑ֈ的请求给予一个“服务器忙”的提示后将其简单抛弃。这 个就够忙zM늚?jin)?br />然后Q结合链表结构实C个线E池Q给池一个初始容量。如果该池满Q以x2的策略将池的定w动态增加一倍,依此cLQ直到ȝE数服务辑ֈpȝ能力上限Q?之后U程池容量不在增加,所有请求将{待一个空余的q回U程。每从池中得C个线E,该线E就开始最hq行GIS信息的服务,如取坐标、取地图Q等{?服务完成后,该线E返回线E池l箋(hu)求队列离地后l请求服务,周而复始。当时用矢量链表来暂存请求,用wait()?notify() ?synchronized{原语结合矢量链表实现线E池QdU?00行程序,而且在运行时间较长的情况下服务器不稳定,U程池被取用的线E有异常消失?情况发生。而用util.concurrent相关cM后,仅用?jin)几十行E序完成了(jin)相同的工作而且服务器运行稳定,U程池没有丢qE的情况发生。由 此可见util.concurrent包极大的提高?sh)(jin)开发效率,为项目节省了(jin)大量的时间?br />使用PooledExecutor例子
    import java.net.*;
    /**
    *
    Title:
    * (tng)
    Description: 负责初始化线E池以及(qing)启动服务?/font>
    *
    Copyright: Copyright (c) 2003
    *
    Company:
    * @author not attributable
    * @version 1.0
    */
    public class MainServer {
    //初始化常?br />public static final int MAX_CLIENT=100; //pȝ最大同时服务客h
    //初始化线E池
    public static final PooledExecutor pool =
    new PooledExecutor(new BoundedBuffer(10), MAX_CLIENT); //chanel定w?0,
    //在这里ؓ(f)U程池初始化?jin)一?br />//长度?0的Q务缓冲队列?br />
    public MainServer() {
    //讄U程池运行参?br />pool.setMinimumPoolSize(5); //讄U程池初始容量ؓ(f)5个线E?br />pool.discardOldestWhenBlocked();//对于出队列的请求,使用?jin)抛弃策略?br />pool.createThreads(2); //在线E池启动的时候,初始化了(jin)h一定生命周期的2个“热”线E?br />}

    public static void main(String[] args) {
    MainServer MainServer1 = new MainServer();
    new HTTPListener().start();//启动服务器监听和处理U程
    new manageServer().start();//启动理U程
    }
    }



    cHTTPListener
    import java.net.*;
    /**
    *
    Title:
    *
    Description: 负责监听端口以及(qing)Q务交l线E池处理
    *
    Copyright: Copyright (c) 2003
    * Company:
    * @author not attributable
    * @version 1.0
    */
    public class HTTPListener extends Thread{
    public HTTPListener() {
    }
    public void run(){
    try{
    ServerSocket server=null;
    Socket clientconnection=null;
    server = new ServerSocket(8008);//服务套接字监听某地址端口?br />while(true){//无限循环
    clientconnection =server.accept();
    System.out.println("Client connected in!");
    //使用U程池启动服?br />MainServer.pool.execute(new HTTPRequest(clientconnection));//如果收到一个请求,则从U程池中取一个线E进行服务,d完成后,该线E自动返q线E池
    }
    }catch(Exception e){
    System.err.println("Unable to start serve listen:"+e.getMessage());
    e.printStackTrace();
    }
    }
    }

    关于util.concurrent工具包就有选择的介l到q,更详l的信息可以阅读q些java源代码的API文档。Doug Lea是个很具有“open”精的作者,他将util.concurrent工具包的java源代码全部公布出来,有兴的读者可以下载这些源代码q细 l品呟?

    5    l束?br />以上内容介绍?jin)线E池基本原理以及(qing)设计后台服务E序应考虑到的问题Qƈl合实例详细介绍?jin)重要的多线E开发工具包util.concurrent的构架和使用。结合用已有完善的开发包Q后端服务程序的开发周期将大大~短Q同时程序性能也有?jin)保障?br />


    参考文?br />[1] Chad Darby,etc. 《Beginning Java Networking? ?sh)子工业出版C? 2002q??
    [2] util.concurrent 说明文g http://gee.cs.oswego.edu/dl/cpjslides/util.pdf
    [3] q勇.U程池的介绍?qing)简单实?http://www-900.ibm.com/developerWorks/cn/java/l-threadPool/index.shtml
    2002q??br />[4]BrianGoetz. 我的U程到哪里去?jin)http://www-900.cn.ibm.com/developerworks/cn/java/j-jtp0924/index.shtml



    ]]>
    多线E??Concurrent包简?/title><link>http://www.aygfsteel.com/jesson2005/articles/96917.html</link><dc:creator>张金?/dc:creator><author>张金?/author><pubDate>Wed, 31 Jan 2007 05:08:00 GMT</pubDate><guid>http://www.aygfsteel.com/jesson2005/articles/96917.html</guid><wfw:comment>http://www.aygfsteel.com/jesson2005/comments/96917.html</wfw:comment><comments>http://www.aygfsteel.com/jesson2005/articles/96917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jesson2005/comments/commentRss/96917.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jesson2005/services/trackbacks/96917.html</trackback:ping><description><![CDATA[ <h2 id="post-15"> <a title="Permanent Link to 多线E??Concurrent包简? rel="bookmark">多线E??Concurrent包简?/a> </h2> <p> <strong>Util.concurrent工具包概q?/strong> <br /> <strong>Doug Lea</strong> <br />State University of New York at Oswego<br />dl@cs.oswego.edu</p> <p>http://gee.cs.oswego.edu</p> <p>译Q?/p> <p>Cocia Lin(cocia@163.com)</p> <p>Huihoo.org</p> <p>原文</p> <p>http://gee.cs.oswego.edu/dl/cpjslides/util.pdf</p> <p>要点<br />–目标和l构</p> <p>–主要的接口和实?/p> <p>Sync:获得/释放(acquire/release) 协议</p> <p>Channel:攄/取走(put/take) 协议</p> <p>Executor:执行Runnabled</p> <p>–每一个部分都有一些关联的接口和支持类</p> <p>–简单的涉及(qing)其他的类和特?/p> <p>目标<br />–一些简单的接口</p> <p>-但是覆盖大部分程序员需要小?j)处理代码的问?/p> <p>?高质量实?/p> <p>-正确的,保守的,有效率的Q可UL?/p> <p>–可能作为将来标准的基础</p> <p>-获取l验和收集反馈信?/p> <p>Sync<br />?acquire/release协议的主要接?/p> <p>-用来定制锁,资源理Q其他的同步用?/p> <p>- 高层抽象接口</p> <p>- 没有区分不同的加锁用?/p> <p>–实?/p> <p>-Mutex, ReentrantLock, Latch, CountDown,Semaphore, WaiterPreferenceSemaphore,FIFOSemaphore, PrioritySemaphore</p> <p>n q有Q有几个单的实现Q例如ObservableSync, LayeredSync</p> <p>独占?br /><code>try {</code></p> <p>lock.acquire();</p> <p>try {</p> <p>action();</p> <p>}</p> <p>finally {</p> <p>lock.release();</p> <p>}</p> <p>}</p> <p>catch (InterruptedException ie) { ... }</p> <p>?Java同步块不适用的时候用它</p> <p>- 时Q回退(back-off)</p> <p>- 保可中?/p> <p>- 大量q速锁?/p> <p>- 创徏Posix风格应用(condvar)</p> <p> <a id="more-15"> </a> </p> <p>独占例子<br /><code>class ParticleUsingMutex {</code></p> <p>int x; int y;</p> <p>final Random rng = new Random();</p> <p>final Mutex mutex = new Mutex();</p> <p>public void move() {</p> <p>try {</p> <p>mutex.acquire();</p> <p>try { x += rng.nextInt(2)-1; y += rng.nextInt(2)-1; }</p> <p>finally { mutex.release(); }</p> <p>}</p> <p>catch (InterruptedException ie) {</p> <p>Thread.currentThread().interrupt(); }</p> <p>}</p> <p>public void draw(Graphics g) {</p> <p>int lx, ly;</p> <p>try {</p> <p>mutex.acquire();</p> <p>try { lx = x; ly = y; }</p> <p>finally { mutex.release(); }</p> <p>}</p> <p>catch (InterruptedException ie) {</p> <p>Thread.currentThread().interrupt(); return; }</p> <p>g.drawRect(lx, ly, 10, 10);</p> <p>}</p> <p>}</p> <p>回退(Backoff)例子<br /><code>class CellUsingBackoff {</code></p> <p>private long val;</p> <p>private final Mutex mutex = new Mutex();</p> <p>void swapVal(CellUsingBackoff other)</p> <p>throws InterruptedException {</p> <p>if (this == other) return; // alias check</p> <p>for (;;) {</p> <p>mutex.acquire();</p> <p>try {</p> <p>I f (other.mutex.attempt(0)) {</p> <p>try {</p> <p>long t = val;</p> <p>val = other.val;</p> <p>other.val = t;</p> <p>return;</p> <p>}</p> <p>finally { other.mutex.release(); }</p> <p>}</p> <p>}</p> <p>finally { mutex.release(); };</p> <p>Thread.sleep(100); // heuristic retry interval</p> <p>}</p> <p>}</p> <p>}</p> <p>d?br />interface ReadWriteLock {</p> <p>Sync readLock();</p> <p>Sync writeLock();</p> <p>}</p> <p>?理一寚w</p> <p>- 和普通的锁一L(fng)使用?fn)?/p> <p>?寚w合类很有?/p> <p>-半自动的方式实现SyncSet, SyncMap, ?/p> <p>?实现者用不同的锁策?/p> <p>- WriterPreference, ReentrantWriterPreference,</p> <p>ReaderPreference, FIFO</p> <p>ReadWriteLock例子<br />?C在读写锁中执行Q何Runnable的包装类</p> <p>class WithRWLock {</p> <p>final ReadWriteLock rw;</p> <p>public WithRWLock(ReadWriteLock l) { rw = l; }</p> <p>public void performRead(Runnable readCommand)</p> <p>throws InterruptedException {</p> <p>rw.readLock().acquire();</p> <p>try { readCommand.run(); }</p> <p>finally { rw.readlock().release(); }</p> <p>}</p> <p>public void performWrite(? // similar</p> <p>}</p> <p>闭锁(Latch)<br />?闭锁是开始时讄为false,但一旦被讄为trueQ他永q保持true状?/p> <p>- 初始化标?/p> <p>- 结束定?/p> <p>- U程中断</p> <p>- 事g出发指示?/p> <p>?CountDown和他有点cMQ不同的是,CountDown需要一定数量的触发讄Q而不是一?/p> <p>?非常单,但是q泛使用的类</p> <p>- 替换Ҏ(gu)犯错的开发代?/p> <p>Latch Example 闭锁例子<br />class Worker implements Runnable {</p> <p>Latch startSignal;</p> <p>Worker(Latch l) { startSignal = l; }</p> <p>public void run() {</p> <p>startSignal.acquire();</p> <p>// ?doWork();</p> <p>}</p> <p>}</p> <p>class Driver { // ?/p> <p>void main() {</p> <p>Latch ss = new Latch();</p> <p>for (int i = 0; i < N; ++i) // make threads</p> <p>new Thread(new Worker(ss)).start();</p> <p>doSomethingElse(); // don’t let run yet</p> <p>ss.release(); // now let all threads proceed</p> <p>}</p> <p>}</p> <p>信号(Semaphores)<br />-- 服务于数量有限的占有?/p> <p>- 使用许可数量构造对?通常?)</p> <p>- 如果需要一个许可才能获取,{待Q然后取C个许?/p> <p>- 释放的时候将许可d回来</p> <p>-- 但是真正的许可ƈ没有转移(But no actual permits change hands.)</p> <p>- 信号量仅仅保留当前的计数?/p> <p>-- 应用E序</p> <p>- 锁:(x)一个信号量可以被用作互斥体(mutex)</p> <p>- 一个独立的{待~存或者资源控制的操作</p> <p>- 设计pȝ是想忽略底层的系l信?/p> <p>-- (phores ‘remember?past signals)C已经消失的信号量</p> <p> <!--more--> </p> <p>信号量例?br />class Pool {</p> <p>ArrayList items = new ArrayList();</p> <p>HashSet busy = new HashSet();</p> <p>final Semaphore available;</p> <p>public Pool(int n) {</p> <p>available = new Semaphore(n);</p> <p>// ?somehow initialize n items ?</p> <p>}</p> <p>public Object getItem() throws InterruptedException {</p> <p>available.acquire();</p> <p>return doGet();</p> <p>}</p> <p>public void returnItem(Object x) {</p> <p>if (doReturn(x)) available.release();</p> <p>}</p> <p>synchronized Object doGet() {</p> <p>Object x = items.remove(items.size()-1);</p> <p>busy.add(x); // put in set to check returns</p> <p>return x;</p> <p>}</p> <p>synchronized boolean doReturn(Object x) {</p> <p>return busy.remove(x); // true if was present</p> <p>}</p> <p>}</p> <p>屏障(Barrier)<br />?多部分同步接?/p> <p>- 每一部分都必ȝ待其他的分不撞倒屏?/p> <p>?CyclicBarrierc?/p> <p>- CountDown的一个可以重新设|的版本</p> <p>- 对于反复划分法很有?iterative partitioning algorithms)</p> <p>?Rendezvousc?/p> <p>- 一个每部分都能够和其他部分交换信息的屏?/p> <p>- 行ؓ(f)cM同时的在一个同步通道上put和take</p> <p>- 对于资源交换协议很有?resource-exchange protocols)</p> <p>通道(Channel)<br />–ؓ(f)~冲Q队列等服务的主接口</p> <p>?具体实现</p> <p>- LinkedQueue, BoundedLinkedQueue,BoundedBuffer, BoundedPriorityQueue,SynchronousChannel, Slot</p> <p>通道属?br />?被定义ؓ(f)Puttable和Takable的子接口</p> <p>- 允许安装生?消费者模式执?/p> <p>?支持可超时的操作offer和poll</p> <p>- 当超时值是0Ӟ可能?x)被d</p> <p>- 所有的Ҏ(gu)能够抛出InterruptedException异常</p> <p>?没有接口需要sizeҎ(gu)</p> <p>- 但是一些实现定义了(jin)q个Ҏ(gu)</p> <p>- BoundedChannel有capacityҎ(gu)</p> <p>通道例子<br />class Service { // ?/p> <p>final Channel msgQ = new LinkedQueue();</p> <p>public void serve() throws InterruptedException {</p> <p>String status = doService();</p> <p>msgQ.put(status);</p> <p>}</p> <p>public Service() { // start background thread</p> <p>Runnable logger = new Runnable() {</p> <p>public void run() {</p> <p>try {</p> <p>for(;;)</p> <p>System.out.println(msqQ.take());</p> <p>}</p> <p>catch(InterruptedException ie) {} }</p> <p>};</p> <p>new Thread(logger).start();</p> <p>}</p> <p>}</p> <p>q行?Executor)<br />?cMU程的类的主接口</p> <p>- U程?/p> <p>- 轻量U运行框?/p> <p>- 可以定制调度法</p> <p>?只需要支持execute(Runnable r)</p> <p>- 同Thread.startcM</p> <p>?实现</p> <p>- PooledExecutor, ThreadedExecutor,QueuedExecutor, FJTaskRunnerGroup</p> <p>- 相关的ThreadFactorycd许大多数的运行器通过定制属性用线E?/p> <p>PooledExecutor<br />?一个可调的工作者线E池Q可修改得属性如下:(x)</p> <p>- d队列的类?/p> <p>- 最大线E数</p> <p>- 最线E数</p> <p>- 预热(预分?和立?分配)U程</p> <p>- 保持z跃直到工作U程l束</p> <p>?以后如果需要可能被一个新的代?/p> <p>- 饱和(Saturation)协议</p> <p>?dQ丢弃,生者运行,{等</p> <p>PooledExecutor例子<br />class WebService {</p> <p>public static void main(String[] args) {</p> <p>PooledExecutor pool =</p> <p>new PooledExecutor(new BoundedBuffer(10), 20);</p> <p>pool.createThreads(4);</p> <p>try {</p> <p>ServerSocket socket = new ServerSocket(9999);</p> <p>for (;;) {</p> <p>final Socket connection = socket.accept();</p> <p>pool.execute(new Runnable() {</p> <p>public void run() {</p> <p>new Handler().process(connection);</p> <p>}});</p> <p>}</p> <p>}</p> <p>catch(Exception e) { } // die</p> <p>}</p> <p>}</p> <p>class Handler { void process(Socket s); }</p> <p>前景(Future)和可调用(Callable)<br />?Callabe是类gRunnable的接口,用来作ؓ(f)参数和传递结?/p> <p>interface Callable {</p> <p>Object call(Object arg) throws Exception;</p> <p>}</p> <p>?FutureResult理Callable的异步执?/p> <p>class FutureResult { // ?/p> <p>// block caller until result is ready</p> <p>public Object get()</p> <p>throws InterruptedException, InvocationTargetException;</p> <p>public void set(Object result); // unblocks get</p> <p>// create Runnable that can be used with an Executor</p> <p>public Runnable setter(Callable function);</p> <p>}</p> <p>FutureResult例子<br />class ImageRenderer { Image render(byte[] raw); }</p> <p>class App { // ?/p> <p>Executor executor = ? // any executor</p> <p>ImageRenderer renderer = new ImageRenderer();</p> <p>public void display(byte[] rawimage) {</p> <p>try {</p> <p>FutureResult futureImage = new FutureResult();</p> <p>Runnable cmd = futureImage.setter(new Callable(){</p> <p>public Object call() {</p> <p>return renderer.render(rawImage);</p> <p>}});</p> <p>executor.execute(cmd);</p> <p>drawBorders(); // do other things while executing</p> <p>drawCaption();</p> <p>drawImage((Image)(futureImage.get())); // use future</p> <p>}</p> <p>catch (Exception ex) {</p> <p>cleanup();</p> <p>return;</p> <p>}</p> <p>}</p> <p>}</p> <p>其他的类<br />?CopyOnWriteArrayList</p> <p>- 支持整个集合复制时每一个修改的无锁讉K</p> <p>- 适合大多数的多\q播应用E序</p> <p>?工具包还包括?jin)一个java.beans多\q播cȝCOW版本</p> <p>?SynchronizedDouble, SynchronizedInt,SynchronizedRef, etc</p> <p>- cM于java.lang.DoubleQ提供可变操作的同步版本.例如QaddTo,inc</p> <p>- d?jin)一些象swap,commitq样的实用操?/p> <p>未来计划<br />?q发数据构架</p> <p>- 一l繁重线E连接环境下有用的工具集?/p> <p>–支持侧重I/O的程?/p> <p>- 事g机制的IOpȝ</p> <p>?版本的实现</p> <p>- 例如SingleSourceQueue</p> <p>–小q度的改?/p> <p>- 使运行器更容易?/p> <p>?替换</p> <p>- JDK1.3 java.util.Timer 被ClockDaemon取代</p> <img src ="http://www.aygfsteel.com/jesson2005/aggbug/96917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jesson2005/" target="_blank">张金?/a> 2007-01-31 13:08 <a href="http://www.aygfsteel.com/jesson2005/articles/96917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java U程/内存模型的缺陷和增强---摘录《J2SEq阶?/title><link>http://www.aygfsteel.com/jesson2005/articles/96868.html</link><dc:creator>张金?/dc:creator><author>张金?/author><pubDate>Wed, 31 Jan 2007 02:53:00 GMT</pubDate><guid>http://www.aygfsteel.com/jesson2005/articles/96868.html</guid><wfw:comment>http://www.aygfsteel.com/jesson2005/comments/96868.html</wfw:comment><comments>http://www.aygfsteel.com/jesson2005/articles/96868.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jesson2005/comments/commentRss/96868.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jesson2005/services/trackbacks/96868.html</trackback:ping><description><![CDATA[ <h1 class="main_left_block_title" align="center"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Java U程/内存模型的缺陷和增强</h1> <!-- 内容区块 --> <div id="wmqeeuq" class="container" id="articleinfo"> <!--GG Begin:--> <div id="wmqeeuq" class="articleinfo"> <br /> <br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)本文是由JRL写作的《J2SEq阶》一书的部分章节整理而成Q《J2SEq阶》正在写作、完善阶Dc(din)?zhn)阅读后,有Q何徏议、批评,?和我联系 Q或?q儿留言 。《J2SEq阶》写作项目组感谢(zhn)阅L文?<br /><br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) Java在语a层次上实C(jin)对线E的支持。它提供?jin)Thread/Runnable/ThreadGroup{一pd装的类和接口,让程序员可以高效的开发Java多线E应用。ؓ(f)?jin)实现同步,Java提供?jin)synchronize关键字以?qing)object的wait()/notify()机制Q可是在单易用的背后Q应藏着更ؓ(f)复杂的玄机,很多问题是由此而v?</div> <div id="wmqeeuq" class="articlecontent"> <h3> <strong>一、Java内存模型 </strong> </h3> <p style="TEXT-INDENT: 2em">在了(jin)解Java的同步秘密之前,先来看看JMM(Java Memory Model)?<br />Java被设计ؓ(f)跨^台的语言Q在内存理上,昄也要有一个统一的模型。而且Java语言最大的特点是废除?jin)指针,把程序员(sh)痛苦中解脱出来Q不用再考虑内存?sh)用和管理方面的问题?<br />可惜世事M如人意Q虽然JMM设计上方便了(jin)E序员,但是它增加了(jin)虚拟机的复杂E度Q而且q导致某些编E技巧在Java语言中失效?<br /><br />JMM主要是ؓ(f)?jin)规定?jin)U程和内存(sh)间的一些关pR对JavaE序员来说只需负责用synchronized同步关键字,其它诸如与线E?内存?sh)间q行数据交换/同步{繁琐工作均p拟机负责完成。如?所C:(x)Ҏ(gu)JMM的设计,pȝ存在一个主内存(Main Memory)QJava中所有变量都储存在主存(sh)Q对于所有线E都是共享的。每条线E都有自q工作内存(Working Memory)Q工作内存(sh)保存的是d?sh)某些变量的拯Q线E对所有变量的操作都是在工作内存(sh)q行Q线E之间无法相互直接访问,变量传递均需要通过d完成? </p> <p align="center"> <img src="http://www.7880.com/Upload/2006-06/F53D46F47E69FC5E4DB0B9F69366DAB7.gif" /> </p> <p align="left">? Java内存模型CZ?<br /><br />U程若要Ҏ(gu)变量q行操作Q必ȝq一pd步骤Q首先从d复制/h数据到工作内存,然后执行代码Q进行引?赋值操作,最后把变量内容写回Main Memory。Java语言规范(JLS)中对U程和主存(sh)操作定义?个行为,分别为loadQsaveQreadQwriteQassign和useQ这些操作行为具有原子性,且相互依赖,有明的调用先后序。具体的描述请参见JLSW?7章?<br /><br />我们在前面的章节介绍?jin)synchronized的作用,现在Q从JMM的角度来重新审视synchronized关键字?<br />假设某条U程执行一个synchronized代码D,光Ҏ(gu)变量q行操作QJVM?x)依ơ执行如下动作?x) <br />(1) 获取同步对象monitor (lock) <br />(2) 从主存复制变量到当前工作内存 (read and load) <br />(3) 执行代码Q改变共享变量?(use and assign) <br />(4) 用工作内存数据刷C存相兛_?(store and write) <br />(5) 释放同步对象?(unlock) <br />可见Qsynchronized的另外一个作用是保证d内容和线E的工作内存?sh)的数据的一致性。如果没有用synchronized关键字,JVM不保证第2步和W?步会(x)严格按照上述ơ序立即执行。因为根据JLS中的规定Q线E的工作内存和主存(sh)间的数据交换是松耦合的,什么时候需要刷新工作内存或者更C内存内容Q可以由具体的虚拟机实现自行军_。如果多个线E同时执行一D|lsynchronized保护的代码段Q很有可能某条线E已l改动了(jin)变量的|但是其他U程却无法看到这个改动,依然在旧的变量gq行q算Q最l导致不可预料的q算l果?</p> <h3> <strong>二、DCL失效 </strong> </h3> <p style="TEXT-INDENT: 2em">q一节我们要讨论的是一个让Java丢脸的话题:(x)DCL失效。在开始讨Z前,先介l一下LazyLoadQ这U技巧很常用Q就是指一个类包含某个成员变量Q在cd始化的时候ƈ不立即ؓ(f)该变量初始化一个实例,而是{到真正要用到该变量的时候才初始化之?<br />例如下面的代码:(x) <br />代码1 </p> <p class="code"> <strong>class </strong>Foo { <br /><strong>private </strong>Resource res = <strong>null </strong>; <br /><br /><strong>public </strong>Resource getResource() { <br /><strong>if </strong>(res == <strong>null </strong>) <br />res = <strong>new </strong>Resource(); <br /><strong>return </strong>res; <br />} <br />} </p> <p style="TEXT-INDENT: 2em">׃LazyLoad可以有效的减系l资源消耗,提高E序整体的性能Q所以被q泛的用,qJava的缺省类加蝲器也采用q种Ҏ(gu)来加载JavacR?<br />在单U程环境下,一切都相安无事Q但如果把上面的代码攑ֈ多线E环境下q行Q那么就可能?x)出现问题。假设有2条线E,同时执行C(jin)if(res == null)Q那么很有可能res被初始化2ơ,Z(jin)避免q样的Race ConditionQ得用synchronized关键字把上面的方法同步v来。代码如下:(x) <br />代码2 </p> <p class="code"> <strong>Class </strong>Foo { <br />Private Resource res = <strong>null </strong>; <br />Public <strong>synchronized </strong>Resource getResource() { <br />If (res == <strong>null </strong>) <br />res = <strong>new </strong>Resource(); <br /><strong>return </strong>res; <br />} <br />} </p> <p style="TEXT-INDENT: 2em">现在Race Condition解决?jin),一切都很好?<br /><br />N天过后,好学的你偶然看了(jin)一本Refactoring的魔书,深深Z打动Q准备自己尝试这重构一些以前写q的E序Q于是找C(jin)上面q段代码。你已经不再是以前的Java菜鸟Q深知synchronizedq的Ҏ(gu)在速度上要比未同步的方法慢?00倍,同时你也发现Q只有第一ơ调用该Ҏ(gu)的时候才需要同步,而一旦res初始化完成,同步完全没必要。所以你很快把代码重构成了(jin)下面的样子:(x) <br />代码3 </p> <p class="code"> <strong>Class </strong>Foo { <br />Private Resource res = <strong>null </strong>; <br />Public Resource getResource() { <br />If (res == <strong>null </strong>){ <br /><strong>synchronized </strong>( <strong>this </strong>){ <br /><strong>if </strong>(res == <strong>null </strong>){ <br />res = <strong>new </strong>Resource(); <br />} <br />} <br />} <br /><strong>return </strong>res; <br />} <br />} </p> <p style="TEXT-INDENT: 2em">q种看v来很完美的优化技巧就是Double-Checked Locking。但是很遗憾Q根据Java的语a规范Q上面的代码是不可靠的?<br /><br />造成DCL失效的原因之一是编译器的优化会(x)调整代码的次序。只要是在单个线E情况下执行l果是正的Q就可以认ؓ(f)~译器这L(fng)“自作主张的调整代码ơ序”的行ؓ(f)是合法的。JLS在某些方面的规定比较自由Q就是ؓ(f)?jin)让JVM有更多余地进行代码优化以提高执行效率。而现在的CPU大多使用流水线技术来加快代码执行速度Q针对这L(fng)CPUQ编译器采取的代码优化的Ҏ(gu)之一是在调整某些代码的ơ序Q尽可能保证在程序执行的时候不要让CPU的指令流水线断流Q从而提高程序的执行速度。正是这L(fng)代码调整?x)导致DCL的失效。ؓ(f)?jin)进一步证明这个问题,引用一下《DCL Broken Declaration》文章中的例子:(x) <br />设一行Java代码Q?</p> <p class="code">Objects[i].reference = <strong>new </strong><strong>Object </strong>(); </p> <p style="TEXT-INDENT: 2em">l过Symantec JIT~译器编译过以后Q最l会(x)变成如下汇编码在机器中执行:(x) </p> <br />0206106A mov eax,0F97E78h <br />0206106F call 01F6B210 ;为Object甌内存I间 <br />; q回值放在eax?<br />02061074 mov dword ptr [ebp],eax ; EBP 中是objects[i].reference的地址 <br />; 返回的I间地址攑օ其中 <br />; 此时Object未初始?<br />02061077 mov ecx,dword ptr [eax] ; dereference eax所指向的内?<br />; 获得新创建对象的起始地址 <br />02061079 mov dword ptr [ecx],100h ; 下面4行是内联的构造函?<br />0206107F mov dword ptr [ecx+4],200h <br />02061086 mov dword ptr [ecx+8],400h <br />0206108D mov dword ptr [ecx+0Ch],0F84030h <br /><p style="TEXT-INDENT: 2em">可见QObject构造函数尚未调用,但是已经能够通过objects[i].reference获得Object对象实例的引用?<br />如果把代码放到多U程环境下运行,某线E在执行到该行代码的时候JVM或者操作系l进行了(jin)一ơ线E切换,其他U程昄?x)发现msg对象已经不ؓ(f)I,DLazy load的判断语句if(objects[i].reference == null)不成立。线E认为对象已l徏立成功,随之可能?x)用对象的成员变量或者调用该对象实例的方法,最l导致不可预的错误?<br /><br />原因之二是在׃n内存的SMPZQ每个CPU有自qCache和寄存器Q共享同一个系l内存。所以CPU可能?x)动态调整指令的执行ơ序Q以更好的进行ƈ行运ƈ且把q算l果与主内存同步。这L(fng)代码ơ序调整也可能导致DCL失效。回想一下前面对Java内存模型的介l,我们q里可以把Main Memory看作pȝ的物理内存,把Thread Working Memory认ؓ(f)是CPU内部的Cache和寄存器Q没有synchronized的保护,Cache和寄存器的内容就不会(x)?qing)时和主内存的内容同步,从而导致一条线E无法看到另一条线E对一些变量的改动?<br />l合代码3来D例说明,假设Resourcecȝ实现如下Q?</p><p class="code"><strong>Class </strong>Resource{ <br /><strong>Object </strong>obj; <br />} </p><p style="TEXT-INDENT: 2em">即ResourcecL一个obj成员变量引用?jin)Object的一个实例。假?条线E在q行Q其状态用如下化图表示Q? </p><p align="center"><img src="http://www.7880.com/Upload/2006-06/BAD3F09601E2FE28FD1A3FAF243D7AB8.gif" /></p><p align="left">? <br />现在Thread-1构造了(jin)Resource实例Q初始化q程中改动了(jin)obj的一些内宏V退出同步代码段后,因ؓ(f)采取?jin)同步机ӞThread-1所做的改动都会(x)反映C存(sh)。接下来Thread-2获得?jin)新的Resource实例变量resQ由于没有用synchronized保护所以Thread-2不会(x)q行h工作内存的操作。假如之前Thread-2的工作内存(sh)已经有了(jin)obj实例的一份拷贝,那么Thread-2在对obj执行use操作的时候就不会(x)L行load操作,q样一来就无法看到Thread-1对obj的改变,q显然会(x)D错误的运结果。此外,Thread-1在退出同步代码段的时dref和obj执行的写入主存的操作ơ序也是不确定的Q所以即使Thread-2对obj执行?jin)load操作Q也有可能只dobj的初试状态的数据?注:(x)q里的load/use均指JMM定义的操? <br /><br />有很多h不死?j),试图惛_?jin)很多精妙的办法来解册个问题,但最l都p|?jin)。事实上Q无论是目前的JMMq是已经作ؓ(f)JSR提交的JMM模型的增强,DCL都不能正怋用。在William Pugh的论文《Fixing the Java Memory Model》中详细的探讨了(jin)JMM的一些硬伤,更尝试给Z个新的内存模型,有兴深入研I的读者可以参见文后的参考资料?<br /><br />如果你设计的对象在程序中只有一个实例,即singleton的,有一U可行的解决办法来实现其LazyLoadQ就是利用类加蝲器的LazyLoadҎ(gu)。代码如下:(x) </p><p class="code"><strong>Class </strong>ResSingleton { <br /><strong>public </strong><strong>static </strong>Resource res = <strong>new </strong>Resource(); <br />} </p><p style="TEXT-INDENT: 2em">q里ResSingleton只有一个静(rn)态成员变量。当W一ơ用ResSingleton.res的时候,JVM才会(x)初始化一个Resource实例Qƈ且JVM?x)保证初始化的结果?qing)时写入主存,能让其他U程看到Q这样就成功的实C(jin)LazyLoad?<br />除了(jin)q个办法以外Q还可以使用ThreadLocal来实现DCL的方法,但是׃ThreadLocal的实现效率比较低Q所以这U解军_法会(x)有较大的性能损失Q有兴趣的读者可以参考文后的参考资料?<br /><br />最后要说明的是Q对于DCL是否有效Q个为更多的是一U带有学I气的推断和讨论。而从U理论的角度来看Q存取Q何可能共享的变量Q对象引用)(j)都需要同步保护,否则都有可能出错Q但是处处用synchronized又会(x)增加死锁的发生几率,苦命的程序员怎么来解册个矛监֑Q事实上Q在很多Java开源项目(比如Ofbiz/Jive{)(j)的代码中都能扑ֈ使用DCL的证据,我在具体的实践中也没有碰到过因DCL而发生的E序异常。个人的偏好是:(x)不妨先大胆用DCLQ等出现问题再用synchronized逐步排除之。也许有人偏于保守,认ؓ(f)E_压倒一切,那就不妨先用synchronized同步hQ我惌是一个见仁见智的问题Q而且得针对具体的目具体分析后才能决定。还有一个办法就是写一个测试案例来试一下系l是否存在DCL现象Q附带的光盘?sh)提供?jin)q样一个例子,感兴的读者可以自行编译测试。不结果怎样Q这L(fng)讨论有助于我们更好的认识JMMQ养成用多线E的思\d析问题的?fn)惯Q提高我们的E序设计能力?</p><h3><strong>三、JavaU程同步增强?</strong></h3><p style="TEXT-INDENT: 2em">怿你已l了(jin)解了(jin)Java用于同步?板斧Qsynchronized/wait/notifyQ它们的简单而有效。但是在某些情况下,我们需要更加复杂的同步工具。有些简单的同步工具c,诸如ThreadBarrierQSemaphoreQReadWriteLock{,可以自己~程实现。现在要介绍的是牛hDoug Lea的Concurrent包。这个包专门为实现Java高q行E序所开发,可以满我们l大部分的要求。更令h兴奋的是Q这个包公开源代码,可自׃载。且在JDK1.5中该包将作ؓ(f)SDK一部分提供lJava开发h员?<br /><br />Concurrent Package提供?jin)一pd基本的操作接口,包括syncQchannelQexecutor,barrier,callable{。这里将对前三种接口?qing)其部分zc进行简单的介绍?<br /><br /><strong>sync接口Q?</strong>专门负责同步操作Q用于替代Java提供的synchronized关键字,以实现更加灵zȝ代码同步。其cdpd如下Q? </p><p align="center"><img src="http://www.7880.com/Upload/2006-06/456412BE703E36D05B0B06AE0B58B470.jpg" /></p>? Concurrent包Sync接口cdpd <br />SemaphoreQ和前面介绍的代码类|可用于poolcd现资源管理限制。提供了(jin)acquire()Ҏ(gu)允许在设定时间内试锁定信号量,若超时则q回false?<br /><br />MutexQ和Java的synchronizedcMQ与之不同的是,synchronized的同步段只能限制在一个方法内Q而Mutex对象可以作ؓ(f)参数在方法间传递,所以可以把同步代码范围扩大到跨Ҏ(gu)甚至跨对象?<br /><br />NullSyncQ一个比较奇怪的东西Q其Ҏ(gu)的内部实现都是空的,可能是作者认为如果你在实际中发现某段代码Ҏ(gu)可以不用同步Q但是又不想q多改动q段代码Q那么就可以用NullSync来替代原来的Sync实例。此外,׃NullSync的方法都是synchronizedQ所以还是保留了(jin)“内存壁垒”的Ҏ(gu)?<br /><br />ObservableSyncQ把sync和observer模式l合hQ当sync的方法被调用Ӟ把消息通知l订阅者,可用于同步性能调试?<br /><br />TimeoutSyncQ可以认为是一个adaptorQ其构造函数如下:(x) <br />public TimeoutSync(Sync sync, long timeout){…} <br />具体上锁的代码靠构造函C入的sync实例来完成,其自w只负责监测上锁操作是否时Q可与SyncSet合用?<br /><br /><strong>Channel接口Q?</strong>代表一U具备同步控制能力的容器Q你可以从中存放/d对象。不同于JDK中的Collection接口Q可以把Channel看作是连接对象构造?Producer)和对象用?Consumer)之间的一根管道。如图所C:(x) <p align="center"><img src="http://www.7880.com/Upload/2006-06/12E19C54D0295DD4DD67E6E3EE24A833.jpg" /></p>? Concurrent包Channel接口C意?<br /><br />通过和Sync接口配合QChannel提供?jin)阻塞式的对象存取方法(put/takeQ以?qing)可讄d{待旉的offer/pollҎ(gu)。实现Channel接口的类有LinkedQueueQBoundedLinkedQueueQBoundedBufferQBoundedPriorityQueueQSynchronousChannelQSlot{? <p align="center"><img src="http://www.7880.com/Upload/2006-06/C9F4C25C3349969D23F503B120F1D6E8.jpg" /></p>? Concurrent包Channel接口部分cdpd <br /><br />使用Channel我们可以很容易的~写具备消息队列功能的代码,CZ如下Q?<br />代码4 <p></p><p class="code"><strong>Package </strong>org.javaresearch.j2seimproved.thread; <br /><br />Import EDU.oswego.cs.dl.util.concurrent.*; <br /><br /><strong>public </strong><strong>class </strong>TestChannel { <br /><strong>final </strong>Channel msgQ = <strong>new </strong>LinkedQueue(); <em>//log信息队列 </em><br /><br /><strong>public </strong><strong>static </strong><strong>void </strong>main( <strong>String </strong>[] args) { <br />TestChannel tc = <strong>new </strong>TestChannel(); <br />For( <strong>int </strong>i = 0;i < 10;i ++){ <br />Try{ <br />tc.serve(); <br /><strong>Thread </strong>.sleep(1000); <br />} <strong>catch </strong>( <strong>InterruptedException </strong>ie){ <br />} <br />} <br />} <br /><br /><strong>public </strong><strong>void </strong>serve() <strong>throws </strong><strong>InterruptedException </strong>{ <br /><strong>String </strong>status = doService(); <br /><em>//把doService()q回状态放入ChannelQ后台l(f)oggerU程自动d?</em><br />msgQ.put(status); <br />} <br /><br /><strong>private </strong><strong>String </strong>doService() { <br /><em>// Do service here </em><br /><strong>return </strong>"service completed OK! " ; <br />} <br /><br /><strong>public </strong>TestChannel() { <em>// start background thread </em><br /><strong>Runnable </strong>logger = <strong>new </strong><strong>Runnable </strong>() { <br /><strong>public </strong><strong>void </strong>run() { <br /><strong>try </strong>{ <br /><strong>for </strong>(; ; ) <br /><strong>System </strong>.out.println( "Logger: " + msgQ.take()); <br />} <br /><strong>catch </strong>( <strong>InterruptedException </strong>ie) {} <br />} <br />}; <br /><strong>new </strong><strong>Thread </strong>(logger).start(); <br />} <br />} </p><p style="TEXT-INDENT: 2em"><strong>Excutor/ThreadFactory接口: </strong>把相关的U程创徏/回收/l护/调度{工作封装v来,而让调用者只专心(j)于具体Q务的~码工作Q即实现Runnable接口Q,不必昑ּ创徏Threadcd例就能异步执行Q务?<br />使用Executorq有一个好处,是实现U程的“轻量”用。前面章节曾提到Q即使我们实C(jin)Runnable接口Q要真正的创建线E,q是得通过new Thread()来完成,在这U情况下QRunnable对象(d)和Thread对象(U程)??的关pR如果Q务多而简单,完全可以l每条线E配备一个Q务队列,让Runnable对象(d)和Executor对象变成n:1的关pR用了(jin)ExecutorQ我们可以把上面两种U程{略都封装到具体的Executor实现中,方便代码的实现和l护?<br />具体的实现有: PooledExecutorQThreadedExecutorQQueuedExecutorQFJTaskRunnerGroup{?<br />cdpd如下Q? </p><p align="center"><img src="http://www.7880.com/Upload/2006-06/4997C67EB89C0D400A4165AD9D004613.jpg" /></p>? Concurrent包Executor/ThreadFactory接口部分cdpd <br />下面l出一D代码,使用PooledExecutor实现一个简单的多线E服务器 <br />代码5 <p></p><p class="code"><strong>package </strong>org.javaresearch.j2seimproved.thread; <br /><strong>import </strong>java.net.*; <br /><strong>import </strong>EDU.oswego.cs.dl.util.concurrent.*; <br /><br /><strong>public </strong><strong>class </strong>TestExecutor { <br /><strong>public </strong><strong>static </strong><strong>void </strong>main( <strong>String </strong>[] args) { <br />PooledExecutor pool = <br /><strong>new </strong>PooledExecutor( <strong>new </strong>BoundedBuffer(10), 20); <br />pool.createThreads(4); <br /><strong>try </strong>{ <br /><strong>ServerSocket </strong>socket = <strong>new </strong><strong>ServerSocket </strong>(9999); <br /><strong>for </strong>(; ; ) { <br /><strong>final </strong>Socket connection = socket.accept(); <br />pool.execute( <strong>new </strong><strong>Runnable </strong>() { <br /><strong>public </strong><strong>void </strong>run() { <br /><strong>new </strong>Handler ().process(connection); <br />} <br />}); <br />} <br />} <br /><strong>catch </strong>( <strong>Exception </strong>e) {} <em>// die </em><br />} <br /><strong>static </strong><strong>class </strong>Handler { <br /><strong>void </strong>process( Socket s){ <br />} <br />} <br />} </p><p style="TEXT-INDENT: 2em">限于幅Q这里只是蜻蜓点水式的介l了(jin)Concurrent包,事实上还有相当多有用的接口和cL有提刎ͼ我们的配套光盘(sh)附带?jin)Concurrent包和源代码,感兴的读者可以自行分析?</p></div> </div> <img src ="http://www.aygfsteel.com/jesson2005/aggbug/96868.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jesson2005/" target="_blank">张金?/a> 2007-01-31 10:53 <a href="http://www.aygfsteel.com/jesson2005/articles/96868.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʤ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ԭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">齭</a>| <a href="http://" target="_blank">˳ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">˼</a>| <a href="http://" target="_blank">Ϲ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Դ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʯ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">廪</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¡</a>| <a href="http://" target="_blank">潭</a>| <a href="http://" target="_blank">޳</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>