ExecutorService:调用future.get(long,TimeUnit)不会导致排队的Callable运行

时间:2013-04-16 14:12:26

标签: executorservice

我尝试通过使用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之后,队列大小是相同的(一)。在我的程序中,只有一个线程将可调用任务提交给ExecutorService,同一个线程也将检索结果。 更重要的是,这里有一个更奇怪的问题:没有调用Callable.call()方法,因为如果它被调用,我会得到一条日志消息:

log.info("Starting to resolve. Host is: " + target + " .Port is: " + port);

那么在调用Callable时,future.get(long,TimeUnit)方法如何抛出TimeoutException?

1 个答案:

答案 0 :(得分:0)

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

是非中断阻止呼叫!

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

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

我尝试模拟一个长时间运行的DNS查询,我修改了resolv.conf,如下所示: nameserver X.X.X.X //此地址没有有效的DNS服务器! 选项超时:30 我想让DNS客户端阻止一段时间,然后再给我一个否定/肯定的回复。

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

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