0

我尝试通过使用 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 呢?

4

1 回答 1

0

以下调用进行 DNS 查询: 1/ new InetSocketAddress(String, int) - 名称查找 2/ InetAddress.getByName(String) - 名称查找 3/ InetAddress.getHostName() - 反向名称查找

是不可中断的阻塞调用!

正如我之前所说,我使用由单个线程组成的线程池。我没有意识到有必要有多个线程

因此,如果我从future.get(long, TimeUnit)调用中捕获 TimeoutException,然后我尝试通过调用future.cancel(boolean)来取消正在进行的任务......我不会停止单个正在运行的线程是在做。

我尝试模拟一个长时间运行的 DNS 查询,并像这样修改了 resolv.conf:nameserver XXXX //此地址没有有效的 DNS 服务器!options timeout:30 我希望 DNS 客户端在返回否定/肯定响应之前阻止一段时间。

我已经对我的应用程序进行了负载测试......这完全是一场灾难!那是因为我有一个单独的线程来解析这些 DNS 查询并且调用future.get(long, TimeUnit)并没有让它停止!

当然,我可以增加线程池的大小。我已经这样做了,它解决了我的问题。但是......在我的池大小中有多个线程来解析这些 DNS 查询似乎很愚蠢,因为只有一个线程提交应该解决 DNS 查询的 Callables,并且同一个线程也会得到结果.

于 2013-04-17T12:47:26.613 回答