一、框架代码的实现
使用Socket是最完美的的远程连接超时设置技术,下面是创建Socket对象的代码:
建立连接一般的写法是:
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
而要定制超时的写法则为:
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
这种写法使用了底层的socket技术。如果使用JMX远程管理API, 通常不能访问socket。如果一定要使用这种技术的话,需颇费一番周折。其工作量取决于采用的连接协议。
很多情况下,可采用简单而通用的技术——即在另外的线程空间创建一个远程连接,然后等待线程结束。如果超过timeout时间设置而线程仍未结束,则直接将线程舍弃。虽然仍然要在两分钟后才能知晓远程系统已死机,但在这段时间程序可继续作别的事情。
这种做法最适合于远程连接一台机器的情况。如果应用程序需要同时创建多个远程连接,舍弃线程的做法要慎用,因为很可能会遇到必须舍弃很多线程的情况。
在Java SE 5平台上,java.util.concurrent包是作为管理线程创建和通讯的。最简易的方式是单线程执行器。
以下方法用于连接一给定的JMXServiceURL,超时设置为5秒:
JMXConnector jmxc = connectWithTimeout(jmxServiceURL, 5, TimeUnit.SECONDS);
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
这个方法最初的版本:
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
值得注意的是,发送给邮箱的只有一个对象。包括三种情况:
(1)如果连接尝试在时限内完成,连接器对象发送给邮箱,并返回给调用者
(2)如果超时,主线程会向邮箱发送一个任意对象(空字符串,或任意其它对象),从而通知连接线程连接已经超时,并关闭新建的连接。
(3)如果超时刚好在连接建立的同时发生,主线程又发现邮箱已满,在这种情况下主线程会将连接器对象捡起并返回。
以上代码仅是框架,增加几处细节可使代码更加完善。
首先增加异常处理。一个连接尝试的结果可能是异常而不是JMXConnector。虽然并不改变代码的逻辑,但增加了代码的复杂性。
主线程调用BlockingQueue.poll则抛出异常InterruptedException,代码必须处理这异常。
其次是在完成连接后清除连接线程。框架代码没有对ExecutorService调用shutdown()方法,所以每次调用connectWithTimeout时,都生成一个新的单线程执行器对象及其线程。垃圾收集器可能会会受这些执行器对象和线程,但不该依赖于这种可能性的因素。
关于线程还有些微妙之处,框架中的代码会生成一些非守护线程。主线程结束时,因为还有未结束的非守护线程所以应用程序还不能结束。如果有一个线程还在尝试连接而应用程序却结束运行,那个线程就会一直残留到连接尝试超时为止,这一点正是我们要竭力避免的。因此我们的目标变成创建一个守护线程。
详细代码如下
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/InBlock.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
![](http://219.232.114.72/Images/OutliningIndicators/None.gif)
initCause方法虽然只使用了一次,但对于处理没有可抛出参数的那些异常来说却很方便。如果java.util.concurrent包中提供守护线程工厂类DaemonThreadFactory,就不需要每个程序员重新发明轮子了。
代码改进
以上的代码并不能令人十分满意。在用户取消或中断等干扰的情况下,会出现一些特殊的边界条件:已经返回连接结果,而任务却取消了,这样就发生了JMXConnector的泄漏;或者在主线程将要返回的时候,去关闭JMXConnector。
结论
以上介绍了在完全不必考虑底层Socket机制的条件下,如何在创建远程连接时设置超时。这种技术在很多场合下是颇有实用价值的,并且不只局限于JMX 远程API,访问web服务或EJB等场合也可采用。