java - 使用 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 变得无响应。
解决方案
推荐阅读
- python - 有没有办法在没有拦截(PyMC3)的情况下运行 GLM.from_formula ?
- c# - 单击 ComboBox 时如何使用 C# 代码添加 ComboBoxItem
- laravel - 我怎样才能下载文件
- azure-devops - Azure DevOps 经典管道无分支筛选器
- marklogic - 如何在 Optic API 中使用 optic-fn、optic-json、optic-xdmp、optic-xs
- r - 在 R Shiny 中保存模式弹出窗口的内容
- android - 谷歌地图加载后 Nativescript webview 崩溃:我如何软件渲染 webview?
- python - Python 列表推导中的“或”是什么意思?
- python - 如何在python中编码特殊字符
- http-status-code-401 - coinbase api 总是 401 未经授权