# JProgressBar actionPerformedMethode und SwingUI thread



## Guest (9. Feb 2009)

Hallo,

ich wollte nach Button Klick in der actionPerformedMethode eine Fortschrittsanzeige mittels einer JProgressBar
realisieren.

in der Art:

actionPerformed() {

1. Fortschrittsanzeige (unbestimmte) erzeugen in Panel A
2. Methodenaufruf, der eine gewisse Zeit benötigt und Ergebnis B liefert
3. Fortschrittsanzeige aus Panel A entfernen und Ergebnis B hinzufügen

}

Nun habe ich mich gewundert, dass dies so nicht funktioniert, da ein neuzeichnen erst möglich ist, wenn mein actionPerformed beendet ist, wie ich hier: http://forums.sun.com/thread.jspa?threadID=427336&tstart=-2  lesen konnte.

Nun die Frage, wo bekomme ich nähere Infos zu diesem Swing UI thread, der mein Neuzeichnen blockiert? Und wieso isr das denn so gelöst (blockieren des neuzeichnens während der actionPerformed Methode)?


----------



## Zed (9. Feb 2009)

Ich hab mich letztens auch damit rumgeschlagen

http://www.java-forum.org/de/topic82497_progressbar-problem.html


----------



## Ebenius (9. Feb 2009)

Anonymous hat gesagt.:
			
		

> Nun die Frage, wo bekomme ich nähere Infos zu diesem Swing UI thread, der mein Neuzeichnen blockiert? Und wieso isr das denn so gelöst (blockieren des neuzeichnens während der actionPerformed Methode)?


Dieser ominöse _Swing UI thread_ ;-) ist der AWT Event Dispatcher Thread. Dieser Thread versendet alle Events im AWT / Swing. Sowohl die Events zum Zeichnen als auch die MouseEvents, KeyEvents, ActionEvents, etc.

Sun Article: Threads and Swing


----------



## Gast (9. Feb 2009)

Hallo nochmal,

habe den Fortschrittsbalken in einen eigenen Thread ausgelagert, aber auch da wird dieser nicht sofort angezeigt.

Pseudocode:

actionPerformed()
{

startProgressShowThread
// zeitintensive operation

}

Auch hier wird mein Balken nicht angezeigt, obwohl ich nen eigenen Thread hab der ein Fenster mit der ProgressBar erzeugt und diesen Thread noch vor der eigentlichen Operation mittels
"start()" aufrufe. Mein Thread prüft dann mittels eines flags, ob die operation durchgeführt werden konnte und beendet sich dann. Das klappt auch, wenn ich mir das mal mit sysout anschaue. Aber den Balken als solches bekomme ich nicht zu sehen


----------



## Ebenius (9. Feb 2009)

Das ist halt genau verkehrt herum. actionPerformed() wird im Event Dispatch Thread ausgeführt. Der selbe Thread muss auch zeichnen. Wenn Du innerhalb von actionPerformed die zeitintensiven Operationen ausführst, wird während derer nicht gezeichnet. Kannst ja mal das Fenster verkleinern, während die Operation läuft, dann wirst Du sehen, dass auch dabei nicht gezeichnet wird, bis die Operation vorbei ist. Also: Nicht den ProgressShowThread erfinden, sondern die Operation auslagern; zum Beispiel unter Zuhilfenahme der SwingWorker-Klasse. Siehe dazu: Sun Article: Using a Swing Worker Thread.

Ebenius


----------



## Gast (9. Feb 2009)

Hallo Ebenius,

danke für die schnelle Antwort... Werde ich mir anschauen, aber wenn ein Buttonklick nunmal einen zeitintensive Operation auslösen soll? Wieso ist das so "blöd" gemacht in Java?


----------



## Ebenius (9. Feb 2009)

Gast hat gesagt.:
			
		

> [...] aber wenn ein Buttonklick nunmal einen zeitintensive Operation auslösen soll?


Steht doch oben. SwingWorker benutzen.



			
				Gast hat gesagt.:
			
		

> Wieso ist das so "blöd" gemacht in Java?


Bist Du sicher, dass Du den ersten Link auch gelesen hast?


			
				Der Sun-Artikel hat gesagt.:
			
		

> *Why did we implement Swing this way?*
> 
> There are several advantages in executing all of the user interface code in a single thread:
> *Component developers do not have to have an in-depth understanding of threads programming:* Toolkits like ViewPoint and Trestle, in which all components must fully support multithreaded access, can be difficult to extend, particularly for developers who are not expert at threads programming. Many of the toolkits developed more recently, such as SubArctic and IFC, have designs similar to Swing's.
> ...


Ebenius


----------



## Gast (9. Feb 2009)

Hallo,

danke für die zahlreichen Antworten das hat mir schon weitergeholfen.

bisher war es so:

actionPerformed()
{

// Klasse K die mir zeitaufwändige Berechnung zur Verfügung stellt // und eine Liste zurückliefert

List list = K.calculate();

// in actionPerformed wird l aber erneut benötigt
doSomething(list)

}

Damit meine Fortschrittsanzeige funktioniert habe ich meinen Code nun wie folgt abgeändert

actionPerformed()
{
ProgressThread pt;
pt.start()

// in diesem wird in run nun die Methode aus K aufgerufen
CalculateThread { 
         run()
             {
             List list = K.calculate();
             }
}



}


Aber noch immer folgendes Problem...

Mein Fortschritt wird angezeigt, jedoch fährt mein HauptProgramm natürlich fort mit
doSomething(List l)

wie kann ich es schaffen, dass mir der CalculateThread erst mein Ergebnis zurückliefert und ich dann auch wirklich Werte an doSomething übergeben kann?

Wenn ich den Debugger nutze, dann ist an der Stelle doSomething(List l) für die Liste l noch kein Wert aus dem Calculate Thread verfügbar. 

Ich will also den Fortschrittsthread laufen lassen wie bisher, die Methode doSomething jedoch erst aufrufen, wenn mir der CalculateThread das (zeitaufwändig) berechnete Ergebnis zurückgeben konnte.

An der Stelle komme ich leider nicht mehr weiter. Ich habe bisher auch noch nichts grossartig mit Threads gemacht :-(


----------



## der kleine Hans (9. Feb 2009)

Oh nein, mami ich hab mir in die hose gemacht


----------



## SlaterB (9. Feb 2009)

doSomething(List l) 
gehört mit in den Thread, nicht in den ActionListener,

falls der Thread bisher eine eigene Klasse mit für sich abgeschlossenen System ist, dann definiere eine neue anonyme innere Thread-Klasse

new Thread() {
public void run() {
 list =..
 doSomething(list);
}
}.start();
}

quasi so wie man anonyme ActionListener definiert


----------



## Gast (10. Feb 2009)

Hallo nochmal,

generell kann ein Thread aber keine Ergebnisse ala return zurückliefern, oder? Ich müsste mir dann höchtens irgendwelche get Methoden schreiben, oder?

@Ebenius
Danke für das geduldige Antworten. Ich habe auch nochmal den Abschnitt "Why did we implement Swing this way?" gelesen, ihn aber trotzdem noch nicht ganz verstanden...

Ereignisbehandlung (wie beim Klick auf nen Button mittels actionPerformed) wird ja in einem eigenen Thread behandelt. Ich habe aber noch immer nicht verstanden wieso währenddessen kein "neuzeichnen" möglich ist und die GUI somit "still steht". Wäre prima, wenn du das nochmal kurz erklären könntest.


----------



## SlaterB (10. Feb 2009)

>  Ich müsste mir dann höchtens irgendwelche get Methoden schreiben, oder? 

korrekt


----------



## Ebenius (10. Feb 2009)

Gast hat gesagt.:
			
		

> Ereignisbehandlung (wie beim Klick auf nen Button mittels actionPerformed) wird ja in einem eigenen Thread behandelt. Ich habe aber noch immer nicht verstanden wieso währenddessen kein "neuzeichnen" möglich ist und die GUI somit "still steht". Wäre prima, wenn du das nochmal kurz erklären könntest.


Genau das ist es was Du falsch verstanden hast. Alle Event-Handlings (inkl. Zeichnen, actionPerformed, etc.) werden in dem selben Thread (Event Dispatch Thread) sequencell (EventQueue) abgearbeitet. Ist die actionPerformed()-Methode nicht fertig, warten alle anderen Events (auch Neuzeichnen) in der Queue.

Ebenius


----------



## Guest (10. Feb 2009)

Gast hat gesagt.:
			
		

> danke für die schnelle Antwort... Werde ich mir anschauen, aber wenn ein Buttonklick nunmal einen zeitintensive Operation auslösen soll? Wieso ist das so "blöd" gemacht in Java?


Vielleicht, weil alle Betriebssysteme aus gutem Grund ein single-threaded UI Toolkit benutzen, und schon genug daran gescheitert sind ein multi-threaded Toolkit zu entwicheln, gar ein multi-threaded Toolkit für eine VM auf einem nativen single-threaded Toolkit aufzusetzen? Doofe Idee irgendwie? Selber blöd.


----------



## SlaterB (10. Feb 2009)

was gibts da zu scheitern? einfach new Thread {} und fertig,
man müsste beispielsweise nur die eine bestimmte ActionListener-Basisklasse vorgeben,
technisch ist das kein Problem, zumindest kann es der Programmierer ja durch eigene Threads erzwingen,

ob das auf Dauer gut ist und was inhaltlich dagegen spricht, das ist die Frage..


----------



## Ebenius (10. Feb 2009)

SlaterB, es ging grad nur um die Frage, warum das Event Handling im AWT/Swing single-threaded ist... Nicht darum, dass man Funktionen nicht auch in Threads auslagern kann (was man natürlich u.U. tun muss). Oder habe ich Dich hier falsch verstanden?

[edit] Oder hast Du nur übersehen, dass *Gast* nicht gleich *Gast* war?

Ebenius


----------



## SlaterB (10. Feb 2009)

die Frage war
"Ich habe aber noch immer nicht verstanden wieso währenddessen kein "neuzeichnen" möglich ist und die GUI somit "still steht". "

deine technische Antwort 'weil es in einem Thread stattfindet' + zweiter Gast's Antwort 'mehrere Threads wär doch nicht so schön' 
finde ich beide bisher am Thema vorbei,

ich verstehe die Frage so, wie ich sie beantwortet bzw. eher nur neuformuliert habe:
'warum ist nicht jede Aktion eines ActionListeners standardmäßig in einem neuen Thread?'

denn das hätte den Vorteil, dass die GUI nicht blockieren würde,
allerdings auch den Nachteil, dass man wohl GUI-Änderungen korrekterweise in SwingUtilities.invokeLater stecken müsste, 
um auch mal eine Teilantwort zu geben


----------



## Ebenius (10. Feb 2009)

Ah, so verstehe ich was Du meinst. Entschuldige, vielleicht stand ich einfach auf dem Schlauch.


----------



## Gast (11. Feb 2009)

Hallo,

danke an alle, insbesondere Ebenius...

>Genau das ist es was Du falsch verstanden hast. 
>Alle Event-Handlings (inkl. Zeichnen, actionPerformed, etc.) >werden in dem selben Thread (Event Dispatch Thread) sequencell >(EventQueue) abgearbeitet. Ist die actionPerformed()-Methode >nicht fertig, warten alle anderen Events (auch Neuzeichnen) in der >Queue.

Aber wäre es nicht sinnvoller gewesen wenigstens das Zeichnen zuzulassen? Ich hab jetzt zwar das von dir (Ebenius) erläuterte Konzept funktionell verstanden aber noch nicht wieso auch das Zeichnen usw. in diesem Thread abgearbeitet werden, wenn doch damit die ganze GUI blockiert wird. Wäre prima, wenn du darauf nochmal eingehen könntest


----------



## Ebenius (11. Feb 2009)

Beispiel 1: Du vergrößerst ein Fenster. Dein Fenstersystem (Windows, X, ...) schickt daraufhin eine Mitteilung an Deine Applikation (an das AWT Subsystem), dass das Fenster mit dem Handle XYZ seine Größe geändert hat. Danach schickt es üblicher Weise eine Mitteilung, dass das Fenster neu gezeichnet werden soll. Die Anwendung muss darauf reagieren, indem sie erst die Komponenten neu anordnet und dann die Komponenten neu zeichnet.

Beispiel 2: Du möchtest mit der Maus einen Button drücken. Dazu bewegst Du die Maus über den Button.Dein Fenstersystem sendet also an Deine Anwendung die Mitteilung, dass sich die Maus bewegt hat. Das AWT-Subsystem erkennt, dass die Maus sich in den Bereich des Buttons bewegt, sendet daraufhin eine Mitteilung (MOUSE_ENTERED) an den Button, dieser reagiert darauf, indem er einen anderen Rahmen (Rollover Border) bekommt und verlangt danach, dass er neu gezeichnet wird, damit Du den neuen Rahmen siehst. Danach drückst Du auf den Mausknopf. Die Anwendung bekommt vom Fenstersystem die Mitteilung, dass der Mausknopf gedrückt wird, das AWT-Subsystem erkennt, dass dies im Bereich des Buttons passiert, schickt wieder eine Mitteilung an den Button (MOUSE_PRESSED), der Button ändert seinen Status (PRESSED und ARMED), und verlangt dann, neu gezeichnet zu werden.

An beiden Beispielen kann man gut erkennen, dass jedwede Arten von Mitteilungen sinnvoller Weise sequenziell abgearbeitet werden sollten. Oft ergeben sich aus verschiedenen Mitteilungen Statusänderungen in Komponenten und dadurch die Notwendigkeit, diese Komponenten neu zu zeichnen. Beim Zeichnen wiederum müssen die Zustände der Komponenten abgefragt werden (ist der Knopf gedrückt → dunklerer Hintergrund und anderer Rahmen, hat das Textfeld Fokus → evtl. ein anderer Rahmen und ein Cursor, etc.). Das Zeichnen muss synchron zum Abarbeiten der Nachrichten passieren, damit der die Komponenten den richtigen Zustand zeichnen können. Ansonsten würden Probleme auftauchen, dass beispielsweise der Knopf schon den richtigen Rahmen hat, aber noch nicht die richtige Hintergrundfarbe.

Nachdem wir also festgestellt haben, dass sichergestellt sein muss, dass die Nachrichtenbearbeitung synchron zum Zeichnen passieren muss ─ das heißt, dass stets *zwischen* aber *nie während* bearbeiteten Nachrichten gezeichnet werden muss ─ ergibt sich die logische Konsequenz, dass beides im selben Thread stattfindet. Ansonsten müsste man zwei Threads benutzen (Event Dispatcher und Repaint Thread), diese aber gegeneinander synchronsieren, so dass stets der eine wartet während der andere etwas tut. Das wäre erstens aufwändiger, zweitens fehleranfälliger und hätte drittens noch immer das Problem zur Folge, dass nicht gezeichnet werden kann, während Nachrichten abgearbeitet werden.

Verstanden?


----------



## Gast (11. Feb 2009)

Hallo Ebenius,

danke für deine sehr ausführliche Erklärung. Ich versuche mal zusammenzufassen. Viele Events führen zu einer Statusänderung der Komponente welche mit einer visuellen Änderung der Komponente einhergeht. Das zeichnen sollte also nach der Abarbeitung des Events geschehen. Richtig?

OK, wenn aber mein Event nun aber nichts mit der GUI zu tun hat? Beispielsweise wenn der Buttonklick irgend eine Rechenoperation auslöst, die erstmal nichts mit einem grafischen Status zu tun hat könnte ich doch trotzdem z.B. einen Prozessfortschritt darstellen. Dies geht aber leider nicht, da ich ja solange ich in der Methode (actionPerformed) bin nix zeichnen kann, da das Zeichnen ja erst nach der Abarbeitung des Events erfolgt, was ja wie du mir anschaulich erläutern konntest für Events die GUI Änderungen auslösen auch völlig sinnvoll erscheint. Wieso kann ich aber nicht durch ein Schlüsselwort trotzdem auch inerhalb der Eventbehandlung ein Zeichnen anstoßen? Für den Fall des "wartens" in der Eventmethode, was keine GUI Änderung auslöst wäre das doch sinnvoll. Oder hab ich wieder was falsch verstanden?


----------



## Ebenius (11. Feb 2009)

Gast hat gesagt.:
			
		

> danke für deine sehr ausführliche Erklärung. Ich versuche mal zusammenzufassen. Viele Events führen zu einer Statusänderung der Komponente welche mit einer visuellen Änderung der Komponente einhergeht. Das zeichnen sollte also nach der Abarbeitung des Events geschehen. Richtig?


Jupp.



			
				Gast hat gesagt.:
			
		

> OK, wenn aber mein Event nun aber nichts mit der GUI zu tun hat? [...]


Genau dort liegt Dein Denkfehler. Der Event ist ein ActionEvent eines Buttons und gehört ganz genau zur GUI und zu nichts anderem. Wenn Du eine längere Operation ausführst gehört eben diese Operation nicht zur GUI und sollte deshalb eben nicht direkt im EventHandler ablaufen. Ich mache das normaler Weise so: 
	
	
	
	





```
/** Action handler starting my long lasting action */
public void actionPerformed(ActionEvent event) {
  new Thread(new Runnable() {
    public void run() {
      myLongLastingAction();
    }
  }).start();
}

//...

void myLongLastingAction() {
  final int resultA;
  final int resultB;
  try {
    /* wait for ten seconds to simulate a complex calculation */
    Thread.sleep(10 * 1000);
    resultA = 23;
    resultB = 42;
  } catch (InterruptedException ex) {
    /* reset interrupt flag */
    Thread.currentThread().interrupt();
    return;
  }

  /* after calculation let the event dispatch thread update the GUI components */
  invokeOnEDT(new Runnable() {

    @Override
    public void run() {
      label.setText("Result A: " + resultA + " Result B: " + resultB);
    }
  });
}

/**
 * Runs the given runnable on the event dispatch thread and waits for the end
 * of processing before the method returns. If called on the EDT, the runnable's
 * {@code run()} method is simply called. If not called on the EDT, the
 * runnable is passed to the {@code SwingUtilities.invokeAndWait()} method.
 * Any unchecked exception is rethrown.
 *
 * @param doRun the runnable being executed
 */
private static void invokeOnEDTRunnable doRun) {
  if (SwingUtilities.isEventDispatchThread()) {
    doRun.run();
  } else {
    try {
      SwingUtilities.invokeAndWait(doRun);
    } catch (InterruptedException ex) {
      /* reset interrupted flag */
      Thread.currentThread().interrupt();
      return;
    } catch (InvocationTargetException ex) {
      final Throwable targetEx = ex.getTargetException();
      targetEx.fillInStackTrace();
      if (targetEx instanceof RuntimeException) {
        throw (RuntimeException) targetEx;
      } else if (targetEx instanceof Error) {
        throw (Error) targetEx;
      } else {
        assert false : "Must have been an unchecked exception!";
      }
    }
  }
}
```
In Java 6 (ich muss meist noch Java 5 benutzen und weiß daher nicht genau wie man's am besten nutzt) gibt es die SwingWorker-Klasse, mit der man das Problem ähnlich aber schöner lösen kann.

Ebenius


----------



## Gast (12. Feb 2009)

Hallo Ebenius,

danke für deine Geduld...

>Genau dort liegt Dein Denkfehler. Der Event ist ein ActionEvent >eines Buttons und gehört ganz genau zur GUI und zu nichts >anderem.

Das hab ich noch nicht ganz verstanden. Das Event gehört zwar zu einer Komponente (dem Button), also zur GUI, modifiziert doch aber in diesem Fall nicht das Aussehen bzw. den Status der GUI, d.h. ein neuzeichnen wäre in diesem Fall doch möglich, oder nicht. D.h. es ist ja nur kritisch, wenn die actionPerformedMethode eine Änderung an der GUI durchführen  würde wie ein resize oder so...


----------



## Ebenius (12. Feb 2009)

Es ist überhaupt nichts kritisch. Es ist eher ganz einfach... 

Alle Events werden der Reihe nach aus einer Queue gezogen und abgearbeitet. Das ─ wenn man so will ─ oberste Event ist das was zur Zeit abgearbeitet wird. Während Dein Button-Handler arbeitet sieht die EventQueue dann bespielsweise so aus (stark vereinfacht und gekürzt): 
	
	
	
	





```
ActionEvent on Button XYZ ← wird derzeit abgearbeitet
MouseEvent (MOUSE_RELEASED) on Button XYZ
PaintEvent on Button XYZ
...
```
Der PaintEvent wird erst dann bearbeitet werden, wenn die darüber liegenden Events abgearbeitet sind. Der oberste Punkt ist aber Deine laufende actionPerformed()-Methode und die hält alles andere in der EventQueue auf. Da geht es auch nicht um die Art der Tätigkeit der actionPerformed()-Methode (bezieht sich auf: "modifiziert doch aber in diesem Fall nicht das Aussehen ..."), sondern um den trivialen Fakt, dass *ein* Event Dispatch Thread nunmal nur *eine Sache gleichzeitig* machen kann.

Hilft das weiter?

Ebenius


----------



## Gast (12. Feb 2009)

Ja, ich glaub das hilft schon weiter. Du hattest ja weiter oben schon geschrieben, dass die Einführung eines seperaten Paint Thread problematisch ist, da die Events ja ggf. den Status der Komponente das Aussehen ändern. Das es mit der jetzigen Architektur nicht geht, da die Events nur in einem Thread abgearbeitet werden, ist mir auch klar. Aber wie ich schon sagte, wenn ich in meinem Event Handler nichts an der GUI ändere und z.B. nur was berechne, dann wäre es doch sinnvoll ein Zeichnen trotzdem anzustoßen, z.B. durch Einführung eines PaintThreads für genau diesen Fall.

Ich würde es so verstehen...

Die sequentielle Abarbeitung macht Sinn, da die Events größtenteils an der GUI was ändern und ein Zeichenthread somit sowieso warten müsste bis eine Statusänderung der Komponente durchgeführt wird.

Wenn ich jedoch in dem EventHandler nichts an der GUI ändere dann wäre es doch wünschenswert, dass eben genau für diesen Fall ein Zeichnen trotzdem "paralell" dazu erfolgen könnte.


Wie ich also oben schonmal schrieb:
>Viele Events führen zu einer Statusänderung der Komponente >welche mit einer visuellen Änderung der Komponente >einhergeht. Das zeichnen sollte also nach der Abarbeitung des >Events geschehen. Richtig?

Das ist klar und sinnvoll solange die Events was am Aussehen ändern. Wenn mein Event (Buttonklick) nun aber nichts am Aussehen der GUI ändert wäre es doch sinnvoll nun doch sowas wie einen PaintThread zu haben und nicht erst abzuwarten, bis die Methode (actionPerformed) abgearbeitet ist, z.B. um irgenwelche Meldungen auszugeben. Das macht wie gesagt ja nur dann Sinn, wenn wirklich nur Berechnungen durchgeführt werden...

Das es mit der momentanen Architketur (sequentielle Abarbeitung der Events im Dispatch Thread) so natürlich nicht geht hab ich denke ich verstanden. Aber die Frage ist, warum man eben gerade für den Fall falls man doch während ein Event abgearbeitet wird Zeichnen will, nicht eine Lösung eingeführt hat, wie z.B. den Zeichen Thread...


----------



## Gast (12. Feb 2009)

Nachtrag:

Bzgl. eines (Re)Paint Threads schriebst du ja oben:

>hätte drittens noch immer das Problem zur Folge, dass nicht >gezeichnet werden kann, während Nachrichten abgearbeitet >werden.

Das bezog sich ja darauf, dass er warten müsste wenn die Events (wie meistens der Fall) den Status der Komponente manipulieren welcher Auswirkungen auf die GUI hat. Wie gesagt, die Frage steht noch immer: Für diesen Fall leuchtet das ja ein, aber warum wird nicht ein "Spezialfall" zugelassen, wenn das Event dann doch nur "rechnet" und das keine Auswirkungen auf die GUI hat. 

Übrigens nochmal ein grosses DANKE an dich Ebenius, dass du dein Wissen mit Anfängern teilst


----------



## Ebenius (12. Feb 2009)

Es kann nicht so einfach getrennte Abarbeitung von Events und Zeichnen geben. Woher soll denn das AWT-Subsystem wissen, wann ein Event synchron und wann es asynchron abgearbeitet werden muss/kann/darf? Das kann doch keiner automatisch entscheiden. Die einzige Alternative die mir ad hoc dazu einfiele, wäre, alle Komponenten für jede Status-Änderung mit den Zeichenroutinen zu synchronisieren. Das ist aber 
nicht nötig, da der fähige Entwickler gut auch selbst darüber entscheiden kann, wann er eine Operation auslagern muss/soll und wann nicht und
ein unerträglicher Mehraufwand, da ständig synchronisierte Bereiche betreten werden müssen, was eben teuer ist
Es gibt ja Widget-Konzepte die nicht auf einem Single-Thread-Modell aufbauen. In meinen Augen haben die sich nicht durchgesetzt, weil dadurch nichts einfacher sondern alles gefährlicher wird.



			
				Anonymous hat gesagt.:
			
		

> Übrigens nochmal ein grosses DANKE an dich Ebenius, dass du dein Wissen mit Anfängern teilst


Sehr gern. 

Ebenius


----------



## Gast (12. Feb 2009)

Hallo Ebenius für die wie immer schnelle Antwort...

>Es kann nicht so einfach getrennte Abarbeitung von Events und >Zeichnen geben. Woher soll denn das AWT-Subsystem wissen, >wann ein Event synchron und wann es asynchron abgearbeitet >werden muss/kann/darf? Das kann doch keiner automatisch >entscheiden.

Das könnte doch der Programmierer beispielsweise mittels eines Schlüsselwortes o.ä. mitteilen

>ein unerträglicher Mehraufwand, da ständig synchronisierte >Bereiche betreten werden müssen, was eben teuer ist

Das verstehe ich nicht, vorallem das "teuer". Und wieso müssten in diesem Fall ständig synchronisierte Bereiche betreten werden?

Viele Grüße und Danke


----------



## Gast (12. Feb 2009)

Und bitte geh auch nochmal auf das 
>weil dadurch nichts einfacher sondern alles gefährlicher wird. 

ein


----------



## Ebenius (12. Feb 2009)

Multi-Threading ist nie trivial, auch wenn einem Java mit Hilfe des _synchronized_-Schlüsselworts etwas anderes suggerieren mag. Sobald man mehrere Threads auf dieselben Daten loslässt, muss man zwischen den Zugriffen synchronisieren; das heißt, sicherstellen, dass nie einer schreibt während ein anderer die Daten liest oder auch schreibt. Dieser Aufwand ist zur Laufzeit teuer (synchronisierte Bereiche zu betreten kostet erheblich Zeit). Außerdem gibt es für den Programmierer mehr zu beachten, sobald er mit mehreren Threads arbeitet; darin bestehen die Gefahren. Schließlich ist das Thema ─ wie Du am Anfang dieses Threads nachlesen kannst ─ schon mit der Single-Thread-Philosophie schwierig genug; mit höherer Komplexität steigt dann auch das Risiko, Systeme zu benutzen die man nicht versteht.



			
				Gast hat gesagt.:
			
		

> Ebenius hat gesagt.:
> 
> 
> 
> ...


Zum Beispiel über Annotations wäre das prinzipiell möglich. Stellt sich aber noch immer die Frage, warum man das Problem auf diese Weise lösen sollte, wenn es doch mit dem SwingWorker ebenso einfach zu lösen ist.

Ebenius


----------



## Gast (12. Feb 2009)

Hallo Ebenius,

vielen Dank. Wirklich nett. Du solltest Dozent werden 

Was ich noch nicht ganz verstanden habe:
>Dieser Aufwand ist zur Laufzeit teuer (synchronisierte Bereiche zu >betreten kostet erheblich Zeit). Außerdem gibt es für den >Programmierer mehr zu beachten, sobald er mit mehreren >Threads arbeitet; darin bestehen die Gefahren.
Wieso kostet es soviel Zeit synchronisierte Bereiche zu betreten und hast du noch ein Beispiel(szenario) was eine mögliche Gefahr wäre, wenn ich einen Event und einen Paint thread habe und vorher z.B. mittels "Schlüsselwort" dem thread mitgeteilt hätte "Du darfst zeichnen, da diese Methode die GUI nicht verändert"


----------



## Ebenius (12. Feb 2009)

Vorab: Gewöhn Dir mal an, quote-Tags im Forum zu benutzen. Das liest sich gar grausam...



			
				Gast hat gesagt.:
			
		

> Wieso kostet es soviel Zeit synchronisierte Bereiche zu betreten


Es müssen zwei oder mehr Threads in einen Zustand gebracht werden in dem sichergestellt ist, dass nur einer der Threads den Bereich betreten und nicht zufällig zwei die es gleichzeitig probieren. Das kostet einfach auf jedem mir bekannten System Zeit.



			
				Gast hat gesagt.:
			
		

> hast du noch ein Beispiel(szenario) was eine mögliche Gefahr wäre, wenn ich einen Event und einen Paint thread habe und vorher z.B. mittels "Schlüsselwort" dem thread mitgeteilt hätte "Du darfst zeichnen, da diese Methode die GUI nicht verändert"


Da gibt es sicher tausend Varianten wie das schiefgehen kann. Aber da sauge ich mir jetzt mal nichts aus den Fingern, da es ein solches Konzept im Java nicht gibt.

Ebenius


----------



## Gast (13. Feb 2009)

Hallo Ebenius,

ich denke ich habe jetzt die meisten Probleme verstanden. Das grösste Problem ist also das sicherstellen der Konsistenz, wenn mehrere Threads statt nur der eine dispatch Thread konkurrieren.

Was ich jedoch noch nicht ganz verstanden habe:

Wenn ich meine langwierige Berechnung in einem seperaten Thread ausführe und in diesem Thread dann auch gleich das GUI update anstosse, wenn die Berechnung erfolgreich ist, sind dann die Logik (einfach einen Wert berechnen) und die GUI dann nicht miteinander verwoben (Thread muss GUI kennen um z.B. ein Label mit dem entsprechenden Wertz zu setzen)?

Wäre es nicht schöner ähnlich eines Methodenaufrufs, die Möglichkeit zu haben einfach nur den Wert zu berechnen unabhängig von einer (sich möglicherweise) ändernden GUI? D.h. wenn ich mein Ergebniss dann lieber in ein Textfeld schreiben will statt in ein Label muss ich ja im Berechnungsthread rumspielen...

Oder habe ich da wieder was falsch verstanden? ;-) Schonmal danke und einen schönen Freitag


----------



## Ebenius (13. Feb 2009)

Schau Dir nochmal mein Code-Beispiel an: Dieses hier.
In den Zeilen 13 bis 24 ist die Berechnung. An dieser Stelle würde man die Trennung machen, also diese Zeilen rausschmeißen und auf die ausgelagerte Berechnungslogik verweisen. Also zum Beispiel sowas hier: 
	
	
	
	





```
final Berechnung berechnung = new Berechnung();
berechnung.setEingabeWerte(meineEingangsWerte);
berechnung.run();
```
Der Aufbau und Start des Threads gehört in die GUI. Und das Auslesen und Darstellen der Ergebnisse aus der Berechnung sollte dann ein paar Zeilen weiter unten ebenfalls in der GUI passieren. Die Logik kann man aber schön in eine andere Klasse werfen.

So ergibt's Sinn, oder?

Ebenius


----------



## Gast (14. Feb 2009)

Hmm, ok. Also ich bräuchte dann noch sowas wie getEingabeWerte um die Werte für eine Darstellung in der GUI auszulesen?

Und noch ne andere Frage... Ich hab nocheinmal versucht über das Problem mit der Konsistenz bei einem seperaten Zeichen Thread nachgedacht...

angenommen ich würde in meiner Action performed Methode, wie ich es vorgeschlagen habe, mittels eines Schlüsselworts doch einen seperaten Zeichen Thread starten können (da dort z.B. wie bereits diskutiert keine GUI änderung stattfinden würde)... Der Thread würde dann laufen, bis der so markierte Bereich abgearbeitet ist. Da dürften doch keine Konsistenzprobleme entstehen, oder? Denn der Zeichen Thread würde ja nur konsistente Daten nutzen, da er duch die Schlüsselwörter "weiss", dass keine GUI relevanten Daten verändert wurden...

Nur mal so als Gedankenexperiment. Ich hoffe ich nerve dich nicht zu sehr ;-) Schönes WE und Danke


----------



## Ebenius (14. Feb 2009)

Anonymous hat gesagt.:
			
		

> Nur mal so als Gedankenexperiment. Ich hoffe ich nerve dich nicht zu sehr ;-) Schönes WE und Danke


Ehrlich? Es beginnt gerade... ;-) Für so viel Theorie hatte ich gestern zu viel Alkohol.

Ebenius


----------



## Gast (15. Feb 2009)

OK. Dann vielleicht ein andermal  Schönes WE noch


----------

