JavaFX thread is hanging when using ExecutorService












0














I'm trying to write a program that uses Imgur's API to download images based on an account name.



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 is a List of codes that are required to send a GET request to Imgur in order to receive that album's images. The data returned is then used in another method which downloads the images themselves.
Now, all of this works fine, but when the program is making all the GET requests the JavaFX thread hangs (GUI becomes unresponsive). And after all the GET requests have been executed, the JavaFX thread stops hanging and the alert shows up with the correct information.
I just don't understand why the GUI becomes unresponsive when I'm not (I believe I'm not) blocking it's thread and I'm using an ExecutorService to do all the network requests.










share|improve this question


















  • 2




    How is hasRemainingRequests() implemented? BTW: there are several issues with your implementation: Making images volatile only makes sure a replacement of the reference is visible to other threads. There's no guarantee that the HashMap itself is consistent for the threads. Also you read from the the GUI on background threads. Accessing the GUI like this can lead to unexpected results including exceptions. Furthermore 100 is a huge number of threads, especially since they seem to access the same resource (your internet connection).
    – fabian
    Nov 21 '18 at 16:25










  • incThreadCount()/decThreadCount() could also be an issue and I recommend using AtomicInteger
    – fabian
    Nov 21 '18 at 16:26












  • @fabian hasRemainingRequests() sends a requests to the Imgur API, who responds with how many requests the user (IP based) and the client (CLIENT_ID based) are still allowed to make before access to the API is blocked.
    – GodsWithin
    Nov 21 '18 at 16:44












  • 100 threads is indeed a huge number. I wouldn’t be surprised if you are simply starving the JavaFX application thread of CPU time.
    – VGR
    Nov 21 '18 at 17:21










  • @fabian I tested this with lower thread counts as well (4-8), but the hanging kept occuring.
    – GodsWithin
    Nov 21 '18 at 18:01
















0














I'm trying to write a program that uses Imgur's API to download images based on an account name.



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 is a List of codes that are required to send a GET request to Imgur in order to receive that album's images. The data returned is then used in another method which downloads the images themselves.
Now, all of this works fine, but when the program is making all the GET requests the JavaFX thread hangs (GUI becomes unresponsive). And after all the GET requests have been executed, the JavaFX thread stops hanging and the alert shows up with the correct information.
I just don't understand why the GUI becomes unresponsive when I'm not (I believe I'm not) blocking it's thread and I'm using an ExecutorService to do all the network requests.










share|improve this question


















  • 2




    How is hasRemainingRequests() implemented? BTW: there are several issues with your implementation: Making images volatile only makes sure a replacement of the reference is visible to other threads. There's no guarantee that the HashMap itself is consistent for the threads. Also you read from the the GUI on background threads. Accessing the GUI like this can lead to unexpected results including exceptions. Furthermore 100 is a huge number of threads, especially since they seem to access the same resource (your internet connection).
    – fabian
    Nov 21 '18 at 16:25










  • incThreadCount()/decThreadCount() could also be an issue and I recommend using AtomicInteger
    – fabian
    Nov 21 '18 at 16:26












  • @fabian hasRemainingRequests() sends a requests to the Imgur API, who responds with how many requests the user (IP based) and the client (CLIENT_ID based) are still allowed to make before access to the API is blocked.
    – GodsWithin
    Nov 21 '18 at 16:44












  • 100 threads is indeed a huge number. I wouldn’t be surprised if you are simply starving the JavaFX application thread of CPU time.
    – VGR
    Nov 21 '18 at 17:21










  • @fabian I tested this with lower thread counts as well (4-8), but the hanging kept occuring.
    – GodsWithin
    Nov 21 '18 at 18:01














0












0








0







I'm trying to write a program that uses Imgur's API to download images based on an account name.



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 is a List of codes that are required to send a GET request to Imgur in order to receive that album's images. The data returned is then used in another method which downloads the images themselves.
Now, all of this works fine, but when the program is making all the GET requests the JavaFX thread hangs (GUI becomes unresponsive). And after all the GET requests have been executed, the JavaFX thread stops hanging and the alert shows up with the correct information.
I just don't understand why the GUI becomes unresponsive when I'm not (I believe I'm not) blocking it's thread and I'm using an ExecutorService to do all the network requests.










share|improve this question













I'm trying to write a program that uses Imgur's API to download images based on an account name.



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 is a List of codes that are required to send a GET request to Imgur in order to receive that album's images. The data returned is then used in another method which downloads the images themselves.
Now, all of this works fine, but when the program is making all the GET requests the JavaFX thread hangs (GUI becomes unresponsive). And after all the GET requests have been executed, the JavaFX thread stops hanging and the alert shows up with the correct information.
I just don't understand why the GUI becomes unresponsive when I'm not (I believe I'm not) blocking it's thread and I'm using an ExecutorService to do all the network requests.







java multithreading javafx executorservice






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 '18 at 15:28









GodsWithin

61




61








  • 2




    How is hasRemainingRequests() implemented? BTW: there are several issues with your implementation: Making images volatile only makes sure a replacement of the reference is visible to other threads. There's no guarantee that the HashMap itself is consistent for the threads. Also you read from the the GUI on background threads. Accessing the GUI like this can lead to unexpected results including exceptions. Furthermore 100 is a huge number of threads, especially since they seem to access the same resource (your internet connection).
    – fabian
    Nov 21 '18 at 16:25










  • incThreadCount()/decThreadCount() could also be an issue and I recommend using AtomicInteger
    – fabian
    Nov 21 '18 at 16:26












  • @fabian hasRemainingRequests() sends a requests to the Imgur API, who responds with how many requests the user (IP based) and the client (CLIENT_ID based) are still allowed to make before access to the API is blocked.
    – GodsWithin
    Nov 21 '18 at 16:44












  • 100 threads is indeed a huge number. I wouldn’t be surprised if you are simply starving the JavaFX application thread of CPU time.
    – VGR
    Nov 21 '18 at 17:21










  • @fabian I tested this with lower thread counts as well (4-8), but the hanging kept occuring.
    – GodsWithin
    Nov 21 '18 at 18:01














  • 2




    How is hasRemainingRequests() implemented? BTW: there are several issues with your implementation: Making images volatile only makes sure a replacement of the reference is visible to other threads. There's no guarantee that the HashMap itself is consistent for the threads. Also you read from the the GUI on background threads. Accessing the GUI like this can lead to unexpected results including exceptions. Furthermore 100 is a huge number of threads, especially since they seem to access the same resource (your internet connection).
    – fabian
    Nov 21 '18 at 16:25










  • incThreadCount()/decThreadCount() could also be an issue and I recommend using AtomicInteger
    – fabian
    Nov 21 '18 at 16:26












  • @fabian hasRemainingRequests() sends a requests to the Imgur API, who responds with how many requests the user (IP based) and the client (CLIENT_ID based) are still allowed to make before access to the API is blocked.
    – GodsWithin
    Nov 21 '18 at 16:44












  • 100 threads is indeed a huge number. I wouldn’t be surprised if you are simply starving the JavaFX application thread of CPU time.
    – VGR
    Nov 21 '18 at 17:21










  • @fabian I tested this with lower thread counts as well (4-8), but the hanging kept occuring.
    – GodsWithin
    Nov 21 '18 at 18:01








2




2




How is hasRemainingRequests() implemented? BTW: there are several issues with your implementation: Making images volatile only makes sure a replacement of the reference is visible to other threads. There's no guarantee that the HashMap itself is consistent for the threads. Also you read from the the GUI on background threads. Accessing the GUI like this can lead to unexpected results including exceptions. Furthermore 100 is a huge number of threads, especially since they seem to access the same resource (your internet connection).
– fabian
Nov 21 '18 at 16:25




How is hasRemainingRequests() implemented? BTW: there are several issues with your implementation: Making images volatile only makes sure a replacement of the reference is visible to other threads. There's no guarantee that the HashMap itself is consistent for the threads. Also you read from the the GUI on background threads. Accessing the GUI like this can lead to unexpected results including exceptions. Furthermore 100 is a huge number of threads, especially since they seem to access the same resource (your internet connection).
– fabian
Nov 21 '18 at 16:25












incThreadCount()/decThreadCount() could also be an issue and I recommend using AtomicInteger
– fabian
Nov 21 '18 at 16:26






incThreadCount()/decThreadCount() could also be an issue and I recommend using AtomicInteger
– fabian
Nov 21 '18 at 16:26














@fabian hasRemainingRequests() sends a requests to the Imgur API, who responds with how many requests the user (IP based) and the client (CLIENT_ID based) are still allowed to make before access to the API is blocked.
– GodsWithin
Nov 21 '18 at 16:44






@fabian hasRemainingRequests() sends a requests to the Imgur API, who responds with how many requests the user (IP based) and the client (CLIENT_ID based) are still allowed to make before access to the API is blocked.
– GodsWithin
Nov 21 '18 at 16:44














100 threads is indeed a huge number. I wouldn’t be surprised if you are simply starving the JavaFX application thread of CPU time.
– VGR
Nov 21 '18 at 17:21




100 threads is indeed a huge number. I wouldn’t be surprised if you are simply starving the JavaFX application thread of CPU time.
– VGR
Nov 21 '18 at 17:21












@fabian I tested this with lower thread counts as well (4-8), but the hanging kept occuring.
– GodsWithin
Nov 21 '18 at 18:01




@fabian I tested this with lower thread counts as well (4-8), but the hanging kept occuring.
– GodsWithin
Nov 21 '18 at 18:01












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415361%2fjavafx-thread-is-hanging-when-using-executorservice%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415361%2fjavafx-thread-is-hanging-when-using-executorservice%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Feedback on college project

Futebolista

Albești (Vaslui)