Threads sind eine tolle Sache... wenn man richtig damit umgeht. Nicht nur, dass Fehler auf Grund von Race Conditions nicht jedes mal auftreten, nein, ab und an helfen einem auch die Exceptions nicht viel weiter, wenn es um das Lokalisieren der Fehlerquelle geht:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException
at javax.swing.LayoutComparator.compare(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(Unknown Source)
at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(Unknown Source)
at java.awt.FocusTraversalPolicy.getInitialComponent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.SequencedEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Dieser Fehler war bei uns in der Arbeit gelegentlich beim Programmstart aufgetreten. Er hat den Programmfunktion nicht beeinschränkt, aber ärgerlich war es dennoch. Also sollte ich mir dem annehmen. Da sämtliche Aufrufe aus der Exception allerdings nicht in unserem Code waren, wusste ich natürlich erstmal nicht, wo ich anfangen soll. Aber wenigstens hilft hier Google ein wenig weiter. Nach ein wenig suchen, stieß ich dann auch recht bald, auf die Ursache: die single-thread rule wurde nicht beachtet.
Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.
Bei uns wurde das ganze dadurch ausgelöst, dass in einem anderen Thread Components aus einem Panel entfernt wurden. Gleichtzeitig hat aber der event-dispatching thread versucht, diese Objekte zu zeichnen. Das das nicht gut gehen kann, sollte man sich recht leicht vorstellen können.
Der Fehler lässt sich auch recht leicht beheben. Man muss nur sämtlichen nebenläufigen Code nach Methoden-Aufrufen von Swing Components durchsuchen (um genau zu sein, muss es nicht jeder Aufruf sein. So sollte ein add() keine Exception verursachen. Der event-dispatching thread würde die Componenten im alten Zustand zeichnen, merken, dass etwas neues dazu gekommen ist und das ganze einfach noch mal zeichnen) und sie dann mit invokeLater() oder auch invokeAndWait() im event-dispatching thread ausführen lassen. Die mehrstündige Suche nach der Ursache wäre uns also erspart geblieben, wenn wir vorher einfach nachgelesen hätten, was man bei Threads und Swing zu beachten hat.
Kommentare