Path: csiph.com!news.mixmin.net!newsreader4.netcologne.de!news.netcologne.de!.POSTED.xdsl-78-35-222-157.netcologne.de!not-for-mail From: Patrick Roemer Newsgroups: de.comp.lang.java Subject: Re: JUnit Test von JButton: Action wird nicht erkannt Date: Tue, 19 Jul 2016 18:59:15 +0200 Organization: news.netcologne.de Distribution: world Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Date: Tue, 19 Jul 2016 16:59:16 +0000 (UTC) Injection-Info: newsreader4.netcologne.de; posting-host="xdsl-78-35-222-157.netcologne.de:78.35.222.157"; logging-data="32244"; mail-complaints-to="abuse@netcologne.de" User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.24) Gecko/20100411 Thunderbird/2.0.0.24 Mnenhy/0.7.6.0 In-Reply-To: Xref: csiph.com de.comp.lang.java:13022 Responding to Christian H. Kuhn: >> Über SwingUtilities#invokeLater(). > > Mit den beiden invoke bin ich auch am Kämpfen. Beide sorgen auf dem EDT > für eine klare Abfolge von Events. Nur invokeAndWait() sorgt aber auch > für eine happens-before-Beziehung zwischen ausgeführten Befehlen auf dem > aufrufenden Thread und dem EDT. Nein! Der Unterschied ist, dass #invokeLater() asynchron ist, d.h. der Aufruf kehrt "sofort" zurück, und der übergebene Codeblock wird dann irgendwann später auf dem EDT ausgeführt. #invokeAndWait() ist synchron, d.h. der Aufruf kehrt erst zurück, wenn der Codeblock auf dem EDT tatsächlich ausgeführt wurde. Wenn kein besonderer Anlass für die Verwendung von #invokeAndWait() vorliegt, ist #invokeLater() zu bevorzugen. In beiden Fällen entsteht *keine* happens-before-Beziehung zwischen irgendwas. In dem Beispielschnipsel, den ich neulich hier hingeklebt habe, hat man eine happens-before-Beziehung zwischen dem Schreiben in die AtomicReference auf dem EDT und dem Lesen dieses Wertes auf dem main-Thread. Und die entsteht eben durch die Verwendung von AtomicReference, weil der Wert darin volatile gehalten wird. Im Prinzip könnte man #invokeAndWait() z.B. dadurch emulieren, dass man am Ende des #invokeLater() übergebenen Blocks ein CountdownLatch triggert und direkt nach dem Aufruf von #invokeLater() auf dieses Latch wartet. Dann hätte man tatsächlich eine happens-before-Beziehung zwischen diesen beiden Latch-Interaktionen. Wenn das noch fuzzy ist, war eine Stunde in der S-Bahn offenkundig nicht ausreichend. :) > Für manche Tests nicht unwichtig, die > darauf warten müssen, dass das EDT-Ereignis auch ausgeführt ist, bevor > der Test funktionieren kann. Dafür wirft invokeAndWait() eine Exception. > In normalem Code kann die problemlos abgefangen und verarbeitet werden; > in Runnables und actionPerformed muss man entweder eine try-catch mit > leerem Catch-Block machen, was alle statischen Codechecker anmeckern, > oder man macht im Catch-Block so Dinge wie > > final Thread thread = Thread.currentThread(); > thread.getUncaughtExceptionHandler().uncaughtException(thread, e); > > die auch keinen Schönheitspreis gewinnen. Das klingt auch noch etwas konfus. In beiden Fällen kann es passieren, dass der übergebene Block eine Exception wirft. Im Fall von #invokeAndWait() wird diese dann, in eine InvocationTargetException gewickelt, an den Aufrufer propagiert. Im Fall von #invokeLater() hat man diese Option nicht, denn der Block wird ja erst ausgeführt, nachdem der Aufruf zurückgekehrt ist. Also bleibt nichts, als diese Exception *im EDT* hochblubbern zu lassen, was wahrscheinlich auch eher unerwünscht ist. Um Exceptions im übergebenen Block muss sich also in jedem Fall Gedanken machen. Das Problem mit leeren catch-Blöcken ist sicher nicht rimäar, dass Codechecker das nicht mögen. Und was ein #invokeAndWait() in einem #actionPerformed() suchen könnte, will ich glaube ich gar nicht so genau wissen... ;) Viele Grüße, Patrick