2010-06-07 9 views
8

Nach Einführung des Java-Speichermodells wurden die Swing-Richtlinien dahingehend geändert, dass alle Swing-Komponenten auf dem EDT instanziiert werden müssen, um einen nicht veröffentlichten Instanzstatus zu vermeiden.Kann man Swing-Klassen in Nicht-EDT-Threads laden?

Was ich nirgendwo finden konnte, ist, ob das Classloading auch auf dem EDT stehen soll oder können wir Key Swing-Klassen in einem Hintergrundthread vorladen? Gibt es dazu eine offizielle Stellungnahme von Sun/Oracle? Gibt es Klassen, von denen bekannt ist, dass sie einen nicht-threadsicheren statischen Zustand besitzen und daher auf EDT geladen werden müssen?

Klärung zu Nemis Frage zu beantworten: Dies ist ein praktisches Problem. Ein beträchtlicher Teil der Startzeit unserer Anwendung ist das Laden von Klassen und das Laden von Schriften/Bildern auf dem EDT. Das meiste davon kann Swing und verwandten Bibliotheken zugeschrieben werden.

Hier ist Som Hintergrund: Wie viele andere Swing-Anwendungen, sind wir beim Start vorkonfigurieren viele Formulare, um die Benutzeroberfläche reaktionsfähiger zu machen. Nach dem Profiling stellten wir fest, dass die tatsächliche Zeit für die Formularkonstruktion relativ schnell ist - was langsam ist, ist das Laden aller Klassen und Schriftarten (Festplattenlesevorgänge sind langsam im Firmen-Setup mit On-Access-Virenscanner, Überwachungsscanner, Überwachungs-Tracker und Gott weiß) was noch auf dem HDD-Treiber angeheftet wurde).

Wir haben versucht, die gleichen Formen in einem Hintergrund-Thread zu konstruieren (Swing-Regeln verletzen) und dann wegwerfen. Sobald wir fertig sind, konstruieren wir dieselben Formulare auf dem EDT, was viel schneller ist, wenn alle Klassen geladen sind und alle anderen Dateien im Plattencache sind. Es funktioniert für uns, und wir werden wahrscheinlich weitermachen, wenn nicht wirklich etwas Schlimmes passiert.

Was ich frage ist, ob dies eine sichere Praxis, eine gute Praxis oder ein Hack ist?

+0

Insbesondere die beiden Singleton-Klassen I waren UIManager und AppContext denken können. Beide Javadocs geben nicht an, ob sie threadsicher sein sollen. AppContext sieht ordnungsgemäß synchronisiert aus, außer dass die isDisposed() -Methode den Status nicht richtig liest (Synchronisation erforderlich). UIManager ist kostenlos für alle, aber sobald der EDT startet, glaube ich nicht, dass ein anderer Thread es mutieren würde. – ddimitrov

+0

Dies ist eine interessante Frage. Ist es rein akademisch oder gibt es ein echtes Problem, das du lösen willst? Ich kann mir keinen guten Grund vorstellen, warum du das tun würdest. – Nemi

+0

@Nemi, fügte der Frage mehr Kontext hinzu – ddimitrov

Antwort

2

Die Beweise scheinen darauf hinzuweisen, dass es sicher ist - aber wiederum, wie ddimitrov in den Kommentaren sagt - die Chancen stehen dafür, keine subtilen Thread-Bugs aufgrund nicht veröffentlichter Änderungen zu finden, weil typische Maschinen nur wenige Kerne haben, und L2/L3-Caches werden gemeinsam genutzt. (L1-Caches sind pro Kern, aber in der Regel sehr klein.)

Wenn Sie sicherstellen wollen, dass kein Problem aufgrund der Hintergrund-Classloading entsteht, dann ist es wahrscheinlich am sichersten, auf Klassen auf der ETD zu bleiben. Um eine Live-Benutzeroberfläche zu verwalten, erstellen Sie einen benutzerdefinierten Klassenlader, der auch Ereignisse zwischen den einzelnen Klassen pumpt. (Abhängigkeiten werden direkt geladen, so dass die Verzögerung nur für die Dauer des Ladens von nur einer Klasse gilt.) Angenommen, dieser Klassenlader ist mit Ihrer Anwendung gepackt, kann er einfach alle Klassenladevorgänge auf seinen Klassenlader verschieben.

Alternativ können sekundäre Ereigniswarteschlangen verwendet werden, die auf separaten Threads ausgeführt werden (z. B. modale Dialoge und die Bibliothek spin). Das bedeutet, Swing kann auf jedem Thread laufen, solange es nur auf einem läuft, und bedeutet, dass es update-konsistent sein muss (oder dass wir alle bisher nur sehr viel Glück gehabt haben!). Auf der Grundlage davon könntest du Laden Sie Ihre Klassen auf den primären EDT und starten Sie einen sekundären EDT, um die UI-Ereignisse zu pumpen, und halten Sie die Benutzeroberfläche so ansprechend - so wie ein modaler Dialog funktioniert. Das Spin-Dienstprogramm pumpt EDT-Ereignisse für Sie oder Sie können einen neuen EDT von Hand erstellen.

+0

Danke, das beantwortet meine Frage. – ddimitrov

+0

Denken Sie darüber nach, Swing auf einem brandneuen EDT zu starten, der aus dem alten erzeugt wurde, ist sicher, da Thread.start() eine sichere Publikation ist. Dann, um die Änderungen zu sehen, müssen wir entweder Thread.join() den temporären Dispatcher oder spawn noch einen anderen Dispatcher (der die neu geladenen Klassen sehen wird) und töten den alten EDT. Klingt chaotisch ... – ddimitrov

+0

Wenn Sie die Spin-Bibliothek verwenden, wird auf die Details geachtet. Ich glaube nicht, dass es so unordentlich ist, wie du befürchtest - der sekundäre EDT kann beendet werden, indem du ein Ereignis an ihn adressierst. Sie tun dies und die Thread.join() nach dem Laden aller Klassen. – mdma

0

Obwohl Sie technisch korrekt sind - ich habe noch nie von einem Problem mit dem Rendern der Formulare in einem anderen Thread gehört, solange Sie nichts mit ihnen tun, sobald sie außer mit dem EDT realisiert werden ursprüngliche Richtlinien).

Früher waren die Richtlinien der Sonne, aber Sun änderte sie so, wie Sie angegeben haben - also bin ich mir sicher, dass jemand einen möglichen Konflikt gefunden oder geschaffen hat, aber ich bin mir auch sicher, dass es schwer werden wird arbeiten immer noch und fast keiner folgt diesen Richtlinien.

In Bezug auf Ihre Frage, ich bin sicher, dass Sie die Klassen laden können, solange Sie keine Objekte instanziieren und immer noch innerhalb der strengsten Richtlinien bleiben.

Der EDT wird nur verwendet, um Gewindekollisionen zu vermeiden, da Swing (vom Entwurf her) mit einem Gewinde versehen ist. Wenn Sie nur die Klassen laden und keine Instanzen erstellen, öffnen Sie sich nicht für Threading-Probleme.

+0

Die Sache, die mich beunruhigt, ist der statische Zustand. Die EDT-Regel löst das Atomaritätsproblem, kümmert sich aber nicht um die Sichtbarkeit - das Setzen eines Feldes auf einen Wert in einem Thread ist nicht garantiert, um von einem anderen Thread sichtbar zu sein, wenn eine korrekte Veröffentlichung erfolgt (zB durch Synchronisation, CAS, etc.) . Beachten Sie, dass die Wahrscheinlichkeit hoch ist, dass zwei Threads auf derselben CPU geplant werden. Mit dem Aufkommen von Multicore-Systemen wird das Problem signifikant werden. – ddimitrov

+0

@ddimitrov Die Sache ist, dass, bis es erkannt wird, es extrem geringe Chance gibt, dass ein anderer Thread Zugriff darauf haben wird. Nun muss es eine Chance geben, aber das einfache Laden der Klassen kann kein Problem verursachen, da in den Klassen noch kein Code ausgeführt wird. Ich bin mir nicht sicher, mit was (wenn überhaupt) Sie nicht einverstanden sind. Wenn Sie es tatsächlich instanziieren - und für immer danach -, sollten Sie nur den EDT verwenden, was nicht impliziert, dass der EDT verwendet werden muss, um die Klassen zu laden, was die Frage des OP war. –

+0

Wenn Sie die Klassen laden, werden statische statische Initialisierungen im Lade-Thread ausgeführt, und alle nicht endgültigen statischen Status unterliegen sicheren Veröffentlichungsregeln. Ich glaube, es gibt in Swing keinen veränderlichen statischen Zustand, aber (wie ich Beispiele nannte) gibt es einige. Ansonsten stimme ich zu, dass die Chancen für ein Problem gering sind, aber wenn es ein Problem gibt, wird es unmöglich sein, zuverlässig zu diagnostizieren oder sogar zu reproduzieren. – ddimitrov

2

Es ist sicher. Siehe: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html (die Einfadenregel)

Wenn Sie Angst haben oder Feedback/Debuggen möchten, sehen Sie sich dieses FEST/Swing-Tool an: "Testen, dass der Zugriff auf GUI-Komponenten im EDT erfolgt") - Es ist eine benutzerdefinierte RepaintManager, die fehlschlägt, wenn Sie die EDT-Zugriffsrichtlinie verletzen.

Sie können diese hilfreich und finden: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

Sie das Laden von Klassen nicht explizit erwähnt, aber sie erklären, was die EDT-Richtlinie geht.

+0

Auch hier spreche ich nicht von Verstößen gegen EDT-Richtlinien. Die EDT-Richtlinie ist keine willkürliche Regel, sie ist aus einem bestimmten Grund da und ich habe das Gefühl, dass sie nicht vollständig ist. Siehe die Antwort von mdma für weitere Details. – ddimitrov

Verwandte Themen