当前位置: 首页 > 知识库问答 >
问题:

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

朱兴学
2023-03-14

我尝试通过使用ThreadPoolExecutor调用在单独线程中执行DNS查询的所有例程来实现异步DNS解析器。

我对可调用对象的定义如下:

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;
                    }
                });

我提交了可调用任务:

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

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

那么,将来如何可能.get(long,TimeUnit)方法在未调用可调用对象时抛出TimeoutException呢?

共有1个答案

拓拔泓
2023-03-14

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

非中断阻塞呼叫!

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

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

我试图模拟一个长时间运行的DNS查询,我修改resolv.conf如下:nameserver X. X. X. X//这个地址没有一个有效的DNS服务器!选项超时: 30我希望DNS客户端在返回给我一个否定/肯定的响应之前阻止一段时间。

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

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

 类似资料:
  • 我在我的android应用程序中使用jackson-core.jar(2.4.2)。我在构建路径中包含了jackson-core.jar(2.4.2)。 当调用新的JsonFactory()时,有一个崩溃:NoClassDefFoundError异常 Logcat输出 12-10 23:45:54.446:E/AndroidRuntime(6287):致命异常:IntentService[File

  • 问题内容: 我有一个带有可观察列表的ComboBox,该列表随用户键入字符或进行选择而更新。当我从ComboBox中选择一个项目并调用我的侦听器事件,然后从ComboBox的ObservableList中调用clear()方法时,引起了我遇到的问题。 完整代码 现在,当我收到错误消息时,ObservableList会按原样出现,但我仍然收到此异常。尝试调试此错误导致我的IDE在调用setAll(运

  • 我希望能够获得我已经提交给执行服务(特别是线程池执行器)的Callable(因此它们不能通过getQueue())。 我试图创建一个子类来覆盖beForeExecute之前的

  • 我正在使用Android应用程序,我想以某种方式打印HashMap的键和值。假设以下是HashMap的内容: 我想以这样一种方式打印HashMap键和值,即字母键首先按字母顺序打印,然后是数字键按升序打印: 我现在做的是: > < li> 获取密钥集并将其保存到数组列表中 使用比较器对数组列表进行排序 使用排序列表打印出地图中的值 这是我的代码: 到目前为止,它还在工作,但是在某些情况下,我没有得

  • 问题内容: 我偶然发现了一个问题,可以总结如下: 当我手动创建线程(即通过实例化)时,将适当地调用它。但是,当我与一起使用时,处理程序将被忽略。我错过了什么? 我期望:消息“未捕获的异常…”的三倍 我得到:消息一次(由手动创建的线程触发)。 在Windows 7和Mac OS X 10.5上用Java 1.6复制。 问题答案: 因为异常不会被捕获。 您的ThreadFactory生成的线程没有直接

  • 我有一个基于spring的java web应用程序,它使用HSQLDB dbms后端在事务中插入大量记录。为了减少为要插入的记录生成主键的往返次数,我想创建一个存储过程,生成主键,在插入之前将其用作标识符。因此,我用以下代码创建了一个存储过程: 有一个序列GENERATE_PKS_SEQ,用于为要插入的记录生成唯一标识符。此存储过程需要一个数字输入(NUMBEROFIDS)来定义要生成的密钥数。