Mam wiele wątków roboczych i GUI JavaFX, który raportuje, co dzieje się w tych wątkach.Złożona współbieżność w JavaFX: użycie ObservableLists i właściwości z wielu wątków roboczych
Istnieje wiele danych udostępnionych między wątkami i należy je zwizualizować. Używam obiektów ObservableList i Property's, aby móc łatwo wyświetlać dane w JavaFX.
Zrobiłem małą przykładową aplikację, aby pokazać coś podobnego do tego, co dzieje się w mojej aplikacji. Ma 2 listy, a wątek roboczy przenosi dane z jednej listy na drugą. Ciąg statusu jest aktualizowany. Pełny przykład kodu można znaleźć na http://codetidy.com/6569/ (kod ten ulega awarii, patrz dalej)
Oto wspólne ObservableList za & Właściwości:
private ObservableList<String> newItems;
private ObservableList<String> readyItems;
private StringProperty status;
Oto jak są one wykorzystywane w JavaFX:
listViewA.setItems(processor.getNewItems());
listViewB.setItems(processor.getReadyItems());
statusLabel.textProperty().bind(processor.getStatus());
Wątek roboczy aktualizuje te listy i właściwości, ale oczywiście musi to zrobić w wątku JavaFX, i tam wszystko staje się brzydkie. Byłoby kod gdybym nie musiał aktualizować na gwincie JavaFX:
Runnable newItemAdder = new Runnable() {
@Override
public void run() {
while(true) {
synchronized (newItems) {
String newItem = checkForNewItem(); //slow
if (newItem != null) {
newItems.add(newItem);
newItems.notify();
}
if (newItems.size() >= 5)
status.set("Overload");
else
status.set("OK");
}
synchronized (readyItems) {
if (readyItems.size() > 10)
readyItems.remove(0);
}
try { Thread.sleep(200); } catch (InterruptedException e) { return; }
}
}
};
new Thread(newItemAdder).start();
Runnable worker = new Runnable() {
@Override
public void run() {
while(true) {
List<String> toProcess = new ArrayList<String>();
synchronized (newItems) {
if (newItems.isEmpty())
try { newItems.wait(); } catch (InterruptedException e) { return; }
toProcess.addAll(newItems);
}
for (String item : toProcess) {
String processedItem = processItem(item); //slow
synchronized (readyItems) {
readyItems.add(processedItem);
}
}
}
}
};
new Thread(worker).start();
Off Oczywiście, niektóre rzeczy są łatwe do rozwiązania z Platform.runLater:
Platform.runLater(new Runnable() {
@Override
public void run() {
synchronized (newItems) {
if (newItems.size() >= 5)
status.set("Overload");
else
status.set("OK");
}
}
});
To dobrze dla properties/list, do których zapisuję tylko w zadaniu, i czytane tylko w interfejsie GUI JavaFX. Ale robi to bardzo skomplikowane, aby zrobić to dla list w tym przykładzie, na którym trzeba synchronizować, czytać i pisać. Musisz dodać wiele platform.runLater i musisz zablokować, dopóki nie zakończy się zadanie "runLater". Powoduje to bardzo złożony i trudny do odczytania i napisania kod (udało mi się uzyskać ten przykład działając w ten sposób, zobacz co mam na myśli: http://codetidy.com/6570/).
Czy istnieją inne sposoby na sprawdzenie, czy mój przykład działa? Byłbym wdzięczny innego rozwiązania lub częściowe rozwiązania ...
Co zmieniłeś w swoich kodach? Czy możesz je pokazać?Ostatni link JewelSea nie działa – AloneInTheDark
@AloneInTheDark Rozglądam się, ale obawiam się, że nie mam oryginalnego kodu przykładowego, ani zmodyfikowanej wersji jewelsea. Wysłałem dodatkową odpowiedź z podsumowaniem rozwiązania. –