首页 > 解决方案 > 使用 ExecutorService 时 JavaFX 线程挂起

问题描述

我正在尝试编写一个程序,该程序使用 Imgur 的 API 根据帐户名称下载图像。

private volatile int threadCount;
private volatile double totalFileSize;
private volatile List<String> albums = new ArrayList<>();
private volatile Map<JSONObject, String> images = new HashMap<>();

private final ExecutorService executorService = Executors.newFixedThreadPool(100, (Runnable r) -> {
        Thread t = Executors.defaultThreadFactory().newThread(r);
        t.setDaemon(true);
        return t;
    });

private void downloadAlbums(List<String> albums) {
    threadCount = 0;
    albums.forEach((albumHash) -> {
        if (hasRemainingRequests()) {
            incThreadCount();
            executorService.execute(() -> {
                try {
                    String responseString;
                    String dirTitle;
                    String albumUrl = URL_ALBUM + albumHash;
                    String query = String.format("client_id=%s", URLEncoder.encode(CLIENT_ID, CHARSET));
                    URLConnection connection = new URL(albumUrl + "?" + query).openConnection();
                    connection.setRequestProperty("Accept-Charset", CHARSET);
                    InputStream response = connection.getInputStream();

                    try (Scanner scanner = new Scanner(response)) {
                        responseString = scanner.useDelimiter("\\A").next();
                        JSONObject obj = new JSONObject(responseString).getJSONObject("data");
                        dirTitle = obj.getString("title");
                        String temp = "";

                        // Get save path from a TextField somewhere else on the GUI
                        ObservableList<Node> nodes = primaryStage.getScene().getRoot().getChildrenUnmodifiable();
                        for (Node node : nodes) {
                            if (node instanceof VBox) {
                                ObservableList<Node> vNodes = ((VBox) node).getChildrenUnmodifiable();
                                for (Node vNode : vNodes) {
                                    if (vNode instanceof DestinationBrowser) {
                                        temp = ((DestinationBrowser) vNode).getDestination().trim();
                                    }
                                }
                            }
                        }
                        final String path = temp + "\\" + formatPath(accountName) + "\\" + formatPath(dirTitle);
                        JSONArray arr = obj.getJSONArray("images");
                        arr.forEach((jsonObject) -> {
                            totalFileSize += ((JSONObject) jsonObject).getDouble("size");
                            images.put((JSONObject) jsonObject, path);
                        });
                    }

                } catch (IOException ex) {
                    //
                } catch (Exception ex) {
                    //
                } finally {
                    decThreadCount();
                    if (threadCount == 0) {
                        Platform.runLater(() -> {

                            DecimalFormat df = new DecimalFormat("#.#");
                            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);//                      714833218
                            alert.setHeaderText("Found " + images.size() + " images (" + (totalFileSize < 1000000000 ? df.format(totalFileSize / 1000000) + " MB)" : df.format(totalFileSize / 1000000000) + " GB)"));
                            alert.setContentText("Proceed with download and save images?");
                            Optional<ButtonType> alertResponse = alert.showAndWait();

                            if (alertResponse.get() == ButtonType.OK) {
                                progressBar.setTotalWork(images.size());
                                executorService.execute(() -> {
                                    for (JSONObject obj : images.keySet()) {
                                        (new File(images.get(obj))).mkdirs();
                                        downloadImage(obj, images.get(obj));
                                    }
                                });
                            }
                        });
                    }
                }
            });
        }
    });
}

albums是向 Imgur 发送 GET 请求以接收该专辑图像所需的代码列表。然后返回的数据用于另一种下载图像的方法。现在,所有这些都可以正常工作,但是当程序发出所有 GET 请求时,JavaFX 线程会挂起(GUI 变得无响应)。在执行完所有 GET 请求后,JavaFX 线程停止挂起并alert显示正确的信息。我只是不明白为什么当我没有(我相信我没有)阻止它的线程并且我正在使用一个ExecutorService来执行所有网络请求时 GUI 变得无响应。

标签: javamultithreadingjavafxexecutorservice

解决方案


推荐阅读