Daten bearbeiten ohne GUI zu blockieren - daten haltung/zurück geben

LokiA

Mitglied
Hi,

Ich bearbeite gerade eine sehr alte Java Swing Applikation und sehe schrecklichen code vor mir.
Um sie besser zu machen muss ich einiges in Threads auslagern, damit die GUI nicht blockiert wird.
Dabei stehe ich vor dem Problem, dass ich Daten in einem Thread bearbeiten muss die aber in der Class liegen und nicht übergeben werden (wobei ich die rückgabe eh auch nciht gelöst hätte)

Bei meiner Suche habe ich folgendes gefunden:
https://www.java-tips.org/java-se-t...ong-running-tasks-in-a-swing-application.html

was ich hier sehe finde ich sehr interessant finde - das GOOD example - hier wird nicht wirklich per "return" etwas zurück gegeben wird sondern von einem weiteren thread die werte im EDT direkt gesetzt (was ich für sehr komfortable halte, da es mir einfacher erscheint als einen "return" basierten weg zu bauen).
Nur verstehe ich daran nicht wieso das erlaubt ist/besser / anders ist als wenn nur über einen Thread liefe oder "bad2". Das sollte doch auch nicht thread-safe sein.
 
Die Lösung "good" startet einen eigenen Thread (new Thread().start()) und setzt nach dem Ende das Ergebnis im EDT (SwingUtilities.invokeLater). Darum wird das als "gut" bezeichnet.
Der EDT arbeitet alle UI spezifischen Sachen ab und mit SwingUtilities#invokeLater kann man Abläufe in den EDT einreihen. Darum ist die Lösung 2 schlecht. Es wird ein Thread#sleep eingebracht der den EDT blockiert.

Die Lösung "good" ist zwar gut im Sinne von Threading, aber nicht im Sinne von gut gelöst. Threads sollte man heutzutage nicht mehr händisch starten und es gibt SwingWorker, die das auch mit dem EDT handlen.
 
Stimmt jetzt sehe ich das auch beim "bad2" - dachte wohl erst dass es ein normaler thread wäre der gestarted wurde.

Ich kenn mich mit Swing nicht so aus. Werd mir den SwingWorker wohl noch ansehen müssen.

Ich würde eben gerne eine Anwendung so abändern, einige langlaufende Objekt Initialisierungen in einen anderen Thread zu verschieben allerdings im EDT auf die Komplettierung zu NICHT Blockierend warten (und die Objekte auch wieder da zu haben). Ist der SwingWorker das richtige? Parallelisieren (sind manchmal 3 manchmal 8 zu initialisierende Objekte) ist ja schon mal nicht möglich, aber auch nicht so wichtig.
 
und sehe schrecklichen code vor mir.
😀

dass ich Daten in einem Thread bearbeiten muss die aber in der Class liegen
Wie soll ich das verstehen?

Parallelisieren (sind manchmal 3 manchmal 8 zu initialisierende Objekte) ist ja schon mal nicht möglich, aber auch nicht so wichtig.
Warum ist parallelisieren nicht möglich?

Am besten ist, Du zeigst das Problem mal anhand von wenig(!) Code.
 
Boahhh, mihe7, bist du früh wach 😀
@LokiA die Kommentare sind etwas aufschlussreich schon:

// We're going to do something that takes a long time, so we
// spin off a thread and update the display when we're done.

// We're going to do the same thing, but not in a
// separate thread.

// The wrong way to use invokeLater().
// The runnable() shouldn't starve the dispatch thread.

Die GUI sollte nicht "blockieren" und mEn brauchen UI Operationen auch nich immer im EDT solange der main T nicht blockiert....
 
Wie soll ich das verstehen?
Ich meinte damit auf die variablen der Klasse aus verschiedenen Threads zu zugreifen, ist ja nciht so gut oder? (Kenne mich mit GUIS, EDT und co ned aus)

Warum ist parallelisieren nicht möglich?
Ich meine jetzt mit dem SwingWorker - der arbeitet das ja hintereinander ab.

... brauchen UI Operationen auch nich immer im EDT solange der main T nicht blockiert....
OK jetzt bin ich verwirrt ... dachte der EDT ist mehr oder weniger in einer GUi applikation der EDT

Java:
public class ApplicationFrame extends JFrame {
// Sample Variable
private DataObject prametersObj;
// some UI components
private JSplitPane splitContentPane;
private JPanel contentPaneProgressBar;
private JPanel contentPaneMainGui;
// ...
// Controller class
private superController controller;
private List<SubModul> subModules;

public static void main(String[] args) {
// process arguments ...
EventQueue.invokeLater(new Runnable() {
public void run() {
ApplicationFrame appFrame = new ApplicationFrame();
appFrame.setArguments(arguments);
appFrame.setVisible(true);
appFrame.setLocationRelativeTo(null);
appFrame.init();
}
});
}

public void init() {
// creates a UI with a ProgressBar and sets in getContentPane()
if (!init_ProgressBar()) {
return;
}

showProgressBar("Initializing the ApplicationFrame ...", 1);
// parses some arguments and sets the Parameters in the prametersObj
if (!init_Parameters()) {
showProgressBar("Initializing parameters failed ...", 1);
return;
}

showProgressBar("Initializing GUI ...", 33);
// creates the rest of the UI, but does not set in getContentPane() (so is still hidden)
if (!init_View()) {
showProgressBar("Initializing GUI failed ...", 33);
return;
}

showProgressBar("Loading Sub modules ...", 66);
// sets superController and inits it
// loads all sub modules & instantiates them and stores them in a list (subModules)
// set up the Menu (entry per subModule + handler -> on klick get view of submodul and put on UI)
if (!load_SubModules()) {
showProgressBar("Loading sub modules failed!", 66);
return;
}

showProgressBar("Initialization finished.", 100);
}
}

Das ist der Code als Beispiel Code.
Die Submodule kenne ich nicht als code (die dürften besser sein).
Die "load_*" Methoden nutzen kein threading etc ...
logischerweise ist dann das "showProgressBar" nutzlos da alles im EDT läuft.

eine einfache lösung wäre wohl nach dem "good" approach vorgehen.
dabei würde ich eine Kette machen:
Init ruft über einen Thread die "load_*" Methoden auf die in einem "invokeLater" call back den ProgressBar updated und den nächsten part der initialiserung startet die dann wieder über einem "invokeLater" call back den ProgressBar updated ... usw.

das sollte klappen (habe tests gemacht) sieht aber unübersichtlich aus und ich frage mich ob das OK ist,
was den zugriff auf die variablen der classe an geht aus verschiednen Threads vs EDT
 
SwingWorker könnte alle Abhängigkeiten via Konstruktor oder setter erhalten ohne von SwingWorker abzuleiten MEn....
 
Musst Du nicht. Schau Dir mal das Beispiel "PrimeNumberTask" in der Doku an (https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html)
Werde ich mir versuchen in den nächsten zwei Wochen an zu sehen - sind aber keine vollständigen Beispiele - was ich daher noch nicht verstehe/unsicher ist - wie es eben mit dem Zugriff auf die variablen aus mehreren Threads ist. Ist das kein Problem?

Danke auch sonst für die Komentare - composition over inheritance - sind sachen die man kennt - aber wenn man so wie ich nicht so oft entwickelt immer weider vergisst - und so bleibt es warm 🙂
 
was ich daher noch nicht verstehe/unsicher ist - wie es eben mit dem Zugriff auf die variablen aus mehreren Threads ist. Ist das kein Problem?

Ich verstehe nicht ganz: auf welche Weise und auf welche Variablen willst Du denn von mehreren Threads aus zugreifen? Es ging doch gerade darum, nicht zu parallelisieren.
 
Ich verstehe nicht ganz: auf welche Weise und auf welche Variablen willst Du denn von mehreren Threads aus zugreifen? Es ging doch gerade darum, nicht zu parallelisieren.
Naja, d.h. aber nur dass nicht parallel zugegriffen wird- zugegriffen wird ja trotzdem.
z.B in meinem Sample code in den einem Thread (der zB. in init_ProgressBar() / load_SubModules()) auf prametersObj oder contentPaneMainGui oder controller.
 
Mal einfach: sobald Du in mehreren Threads auf eine Variable zugreifst und dabei die Variable veränderst, musst Du den Zugriff synchronisieren.

Alles, was UI betrifft, muss im EDT laufen, ggf. musst Du - aus einem anderen Thread heraus - mit der Methode invokeLater in EventQueue bzw. SwingUtilities dafür sorgen. Beim SwingWorker wird vereinfacht, dass man a) aus dem Hintergrund heraus den Fortschritt sicher aktualisieren kann (wird im EDT ausgeführt) und b) ein (Zwischen)-Ergebnis im Hintergund berechnen und im EDT verwenden kann (publish/process bzw. done/get).
 

Zurück
Oben