Java Future.isDone 返回 true,即使它不应该,这会停止程序进程

Java Future.isDone returning true, even though it shouldn't, which halts program progress

我有一个 SwingWorker,它启动一个 LinkedBlockingQueue,将它传递给另一个方法(下面的 PortalDriver),然后在 doInBackground() 方法中读取它。 LinkedBlockingQueue 持有自定义对象的未来(并且它肯定被正确填充)。作为检查,我正在创建的对象(通过 ExecutorService)在构造函数的末尾有一个 println(this),所以我知道它们何时被创建。

问题是,通过 println() 调用(在 doInBackground 和构造函数中),在 doInBackground 的 while 循环中多次成功迭代后,行

System.out.println("future.isDone before get(): " + futureListing.isDone());

打印 true,即使构造函数没有打印它已创建(这仅通过计数就很清楚)。 while 循环永久阻塞,即使其余对象已创建。

private class ReadSchedWorker extends SwingWorker<Void, Listing> {
    private ChromeOptions options = new ChromeOptions();
    private WebDriver driver;
    private LinkedBlockingQueue<Future<Listing>> listingQueue;
    private LoginFactory loginFactory;
    private int year;
    private int month;
    private int day;

    public ReadSchedWorker(Login mediasiteLogin, Login tmsLogin,
                           int year, int month, int day) {
        System.setProperty("webdriver.chrome.driver", "\\private\Home\Desktop\chromedriver.exe");
        listingQueue = new LinkedBlockingQueue<>();
        loginFactory = new LoginFactory(mediasiteLogin, tmsLogin);
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    protected Void doInBackground() throws Exception {
        this.options.addArguments("--disable-extensions");
        driver = new ChromeDriver(options);

        String portalUsername = loginFactory.getPortalUsername();
        String portalPassword = loginFactory.getPortalPassword();
        PortalDriver portalDriver = new PortalDriver(driver, listingQueue);
        portalDriver.getScheduleElements(portalUsername, portalPassword, year, month, day);

        while (!listingQueue.isEmpty()) {
            System.out.println("beginning");
            Future<Listing> futureListing = listingQueue.take();
            System.out.println("future.isDone before get(): " + futureListing.isDone());
            Listing listing = futureListing.get();
            System.out.println("future.isDone after get(): " + futureListing.isDone());
            System.out.println("before publish");
            publish(listing);
            System.out.println("after publish");
        }
        return null;
    }

    @Override
    protected void process(List<Listing> listings) {
        for (Listing listingItem : listings) {
            listingListModel.addElement(listingItem);
        }
    }
}

只是为了完成,这里是 getScheduleElements,它填充了 LinkedBlockingQueue:

public void getScheduleElements(String username, String password, int year, int month, int day) {
    driver.get("https://rxsecure.umaryland.edu/apps/schedules/view/?type=search&searchtype=resource&id=100&start=" +
            year + "-" + month + "-" + day + "&scope=week");
    PortalLoginPage loginPage = PageFactory.initElements(driver, PortalLoginPage.class);
    PortalScheduleEventsWeekPage scheduleEventsWeekPage = loginPage.login(username, password);
    webElementsQueue = scheduleEventsWeekPage.initEventsQueue();

    // doesn't need to be a queue...
    // this is sequential....
    // could do a parallel stream
    while (webElementsQueue.peek() != null) {
        Callable<Listing> callable = new PortalListingCallable(webElementsQueue.poll());
        Future<Listing> future = executor.submit(callable);
        listingQueue.offer(future);
    }

    executor.shutdown();
}

编辑: 我的意思的一个例子(未来没有完成,但通过 doInBackground() 中的 println()s 报告它是):

beginning
future.isDone before get(): true //the future says it done, but the object being created is below
in listing contructor: PHAR580 Pharmacy Law;Specialty Pharmacy 2;Recorded in Mediasite PH S201 2015-04-27T10:00:00.000-04:00 2015-04-27T11:50:00.000-04:00

prints true, even though the constructor hasn't printed that it has been created

很可能您收到了您没有看到的异常或错误。您必须调用 Future.get() 才能看到它。

同时我建议你改变

Future<Listing> future = executor.submit(callable);

Future<Listing> future = executor.submit(new Callable<Listing>() {
    public Listing call() throws Throwable {
        try {
            return callable.call();
        } catch (Throwable t) {
            t.printStackTrace();
            throw t;
        }
    }
});