基于透明Socket的JMX超时设置(转,原谅我懒)
一、框架代码的实现
使用Socket是最完美的的远程连接超时设置技术,下面是创建Socket对象的代码:
建立连接一般的写法是:
Socket s = new Socket(host, port);
而要定制超时的写法则为:
SocketAddress addr = new InetSocketAddress(host, port);
Socket s = new Socket();
s.connect(addr, timeoutInMilliSeconds);
这种写法使用了底层的socket技术。如果使用JMX远程管理API, 通常不能访问socket。如果一定要使用这种技术的话,需颇费一番周折。其工作量取决于采用的连接协议。
很多情况下,可采用简单而通用的技术——即在另外的线程空间创建一个远程连接,然后等待线程结束。如果超过timeout时间设置而线程仍未结束,则直接将线程舍弃。虽然仍然要在两分钟后才能知晓远程系统已死机,但在这段时间程序可继续作别的事情。
这种做法最适合于远程连接一台机器的情况。如果应用程序需要同时创建多个远程连接,舍弃线程的做法要慎用,因为很可能会遇到必须舍弃很多线程的情况。
在Java SE 5平台上,java.util.concurrent包是作为管理线程创建和通讯的。最简易的方式是单线程执行器。
以下方法用于连接一给定的JMXServiceURL,超时设置为5秒:
JMXConnector jmxc = connectWithTimeout(jmxServiceURL, 5, TimeUnit.SECONDS);
这个方法最初的版本:
JMXConnector connectWithTimeout(JMXServiceURL url, long timeout, TimeUnit unit) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<JMXConnector> future = executor.submit(new Callable<JMXConnector>() {
public JMXConnector call() {
return JMXConnectorFactory.connect(url);
}
});
return future.get(timeout, unit);
}
这种解决方案当连接在设置时限内成功创建时是正确的。对于尝试连接很长时间后失败的情况也是正确的。但是如果连接在超时设置之后成功了,则这个连接不可能被调用者使用。
![]()
第二版
以下是第二版的框架
JMXConnector connectWithTimeout(JMXServiceURL url, long timeout, TimeUnit unit) {
final BlockingQueue<Object> mailbox = new ArrayBlockingQueue<Object>(1);
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {
public void run() {
JMXConnector connector = JMXConnectorFactory.connect(url);
if (!mailbox.offer(connector))
connector.close();
}
});
Object result = mailbox.poll(timeout, unit);
if (result == null) {
if (!mailbox.offer(""))
result = mailbox.take();
}
return (JMXConnector) result;
}
值得注意的是,发送给邮箱的只有一个对象。包括三种情况:
(1)如果连接尝试在时限内完成,连接器对象发送给邮箱,并返回给调用者
(2)如果超时,主线程会向邮箱发送一个任意对象(空字符串,或任意其它对象),从而通知连接线程连接已经超时,并关闭新建的连接。
(3)如果超时刚好在连接建立的同时发生,主线程又发现邮箱已满,在这种情况下主线程会将连接器对象捡起并返回。