我尝试通过使用 ThreadPoolExecutor 在单独的线程中调用执行 DNS 查询的所有例程来实现异步 DNS 解析器。
我这样定义 Callable 对象:
public class SocketAddressCreator extends DnsCallable<String, InetSocketAddress> {
private static final Logger log = Logger.getLogger(SocketAddressCreator.class);
private int port;
public SocketAddressCreator(String host, int port) {
super(host);
this.port = port;
}
public InetSocketAddress call() throws Exception {
log.info("Starting to resolve. Host is: " + target + " .Port is: " + port);
long start = System.currentTimeMillis();
**InetSocketAddress addr = new InetSocketAddress(target, port);**
log.info("Time waiting: " + (System.currentTimeMillis() - start));
return addr;
}
}
基本上,可调用对象将尝试将主机名解析为 InetAddress。
然后我定义一个ExecutorService:
executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = Executors.defaultThreadFactory()
.newThread(r);
t.setName("DnsResolver");
t.setDaemon(true);
return t;
}
});
我提交了 Callable 任务:
..............
**Future<V> f = executor.submit(task);**
try {
log.info("Query will be made");
log.info("Queue size: " + executor.getQueue().size());
**result = f.get(timeout, TimeUnit.MILLISECONDS);**
log.info("Queue size: " + executor.getQueue().size());
log.info("Query is finished");
} catch (TimeoutException e) {
boolean isCancelled = f.cancel(true);
log.info("Task was cancelled: " + isCancelled);
log.info("Queue size: " + executor.getQueue().size());
..........
}
..............
然后我看我的程序抛出的日志,它们很奇怪。这是我在解析 DNS 时超时的地方:
DnsResolver : Queue size: 1
DnsResolver : Task was cancelled: true
DnsResolver : Queue size: 1
因此,在提交我的 Callable 对象之后但在调用 future.get(long, TimeUnit) 之前,队列大小为 1。但这对我来说没问题。但是,在我捕获 TimeoutException 并取消 Future 之后,队列大小是相同的(一个)。在我的程序中,只有一个线程将 Callable 任务提交给 ExecutorService,并且同一个线程也将检索结果。不仅如此,这里还有一个更奇怪的问题:Callable.call() 方法没有被调用,因为如果它被调用,我会收到一条日志消息:
log.info("Starting to resolve. Host is: " + target + " .Port is: " + port);
那么,当未调用 Callable 时,future.get(long, TimeUnit) 方法如何抛出 TimeoutException 呢?