Я пытаюсь реализовать асинхронный преобразователь DNS, вызывая все подпрограммы, выполняющие DNS-запрос, в отдельном потоке с помощью ThreadPoolExecutor.
Я определяю вызываемый объект следующим образом:
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
Итак, после отправки моего вызываемого объекта, но до вызова future.get(long, TimeUnit) размер очереди равен 1. Но для меня это нормально. Однако после того, как я поймаю TimeoutException и отменю Future, размер очереди останется прежним (один). В моей программе есть только один поток, который отправляет вызываемые задачи в ExecutorService, и тот же поток также будет получать результаты. Более того, здесь есть еще более странная проблема: метод Callable.call() не вызывается, потому что, если бы он был вызван, я бы получил сообщение журнала:
log.info("Starting to resolve. Host is: " + target + " .Port is: " + port);
Итак, как метод future.get(long, TimeUnit) может генерировать TimeoutException, когда Callable не вызывается?