Programovanie

Swing threading a vlákno na odoslanie udalosti

Predchádzajúca 1 2 3 4 5 Strana 5 Strana 5 z 5

Udržiavanie bezpečnej Swing nite

Posledným krokom pri vytváraní grafického používateľského rozhrania Swing je jeho spustenie. Správny spôsob spustenia Swing GUI sa dnes líši od pôvodne predpísaného prístupu spoločnosti Sun. Tu je citát z dokumentácie spoločnosti Sun:

Po realizácii komponentu Swing by sa mal vo vlákne na odosielanie udalostí spustiť všetok kód, ktorý by mohol ovplyvniť alebo závisieť od stavu tohto komponentu.

Teraz vyhoďte tieto pokyny z okna, pretože okolo toho, keď vyšlo JSE 1.5, sa zmenili všetky príklady na stránkach spoločnosti Sun. Od tej doby je málo známe, že by ste to mali robiť vždy prístup k komponentom Swing vo vlákne na odosielanie udalostí, aby sa zabezpečila ich bezpečnosť vlákna / prístup s jedným vláknom. Dôvod zmeny je jednoduchý: zatiaľ čo váš program môže pristupovať ku komponente Swing mimo vlákna odosielania udalostí skôr, ako je komponent realizovaný, inicializácia používateľského rozhrania Swing môže následne spustiť niečo, čo by mohlo bežať na vlákne udalosti odoslania, pretože komponent / UI očakáva spustenie všetkého vo vlákne na odoslanie udalosti. To, že súčasti grafického používateľského rozhrania bežia na rôznych vláknach, porušujú Swingov jednovláknový programovací model.

Program v zozname 5 nie je celkom realistický, ale slúži mi na vyjadrenie.

Zoznam 5. Prístup k stavu komponentu Swing z viacerých vlákien

import java.awt. *; import java.awt.event. *; importovať javax.swing. *; public class BadSwingButton {public static void main (String args []) {JFrame frame = new JFrame ("Title"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); Tlačidlo JButton = nové JButton („Stlačte tu“); ContainerListener container = new ContainerAdapter () {public void componentAdded (final ContainerEvent e) {SwingWorker worker = new SwingWorker () {protected String doInBackground () throws InterruptedException {Thread.sleep (250); návrat null; } protected void done () {System.out.println ("Na vlákne udalosti?:" + EventQueue.isDispatchThread ()); Tlačidlo JButton = (JButton) e.getChild (); Štítok reťazca = button.getText (); button.setText (štítok + "0"); }}; worker.execute (); }}; frame.getContentPane (). addContainerListener (kontajner); frame.add (tlačidlo, BorderLayout.CENTER); frame.setSize (200, 200); skus {Thread.sleep (500); } catch (InterruptedException e) {} System.out.println ("Chystám sa realizovať:" + EventQueue.isDispatchThread ()); frame.setVisible (true); }}

Všimnite si, že výstup zobrazuje nejaký kód bežiaci na hlavnom vlákne pred realizáciou UI. To znamená, že inicializačný kód je spustený na jednom vlákne, zatiaľ čo iný kód používateľského rozhrania je spustený na vlákne na odosielanie udalostí, ktoré rozbije prístupový model Swing s jedným vláknom:

> java BadSwingButton Vo vlákne udalosti? : true Chystám sa realizovať: false

Program v zozname 5 aktualizuje štítok tlačidla od poslucháča kontajnerov, keď je tlačidlo pridané do kontajnera. Aby bol scenár realistickejší, predstavte si používateľské rozhranie, ktoré v ňom „počíta“ štítky a používa počet ako text v nadpise hranice. Prirodzene by bolo potrebné aktualizovať text nadpisu hranice vo vlákne na odoslanie udalosti. Pre zjednodušenie program iba aktualizuje štítok jedného tlačidla. Aj keď táto funkcia nie je realistická, ukazuje problém s každý Swing program, ktorý sa píše od začiatku Swingových čias. (Alebo aspoň všetci, ktorí nasledovali odporúčaný model vlákna, ktorý sa nachádza v javadocs a online tutoriáloch spoločnosti Sun Microsystems a dokonca aj v mojich vlastných skorých vydaniach programovacích kníh Swing.)

Swing závitovanie hotové správne

Spôsob, ako získať správne fungovanie vlákna Swing, je zabudnúť na pôvodné vyhlásenie spoločnosti Sun. Nerobte si starosti s tým, či je komponent realizovaný alebo nie. Neobťažujte sa pokusom zistiť, či je bezpečný prístup k niečomu mimo vlákna na odoslanie udalosti. Nikdy to tak nie je. Namiesto toho vytvorte celé používateľské rozhranie vo vlákne na odoslanie udalosti. Ak umiestnite celé vytvorenie UI vo vnútri EventQueue.invokeLater () všetky prístupy počas inicializácie sú zaručene vykonané vo vlákne na odoslanie udalosti. Je to také jednoduché.

Zoznam 6. Všetko na svojom mieste

import java.awt. *; import java.awt.event. *; importovať javax.swing. *; public class GoodSwingButton {public static void main (String args []) {Runnable runner = new Runnable () {public void run () {JFrame frame = new JFrame ("Title"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); Tlačidlo JButton = nové JButton („Stlačte tu“); ContainerListener container = new ContainerAdapter () {public void componentAdded (final ContainerEvent e) {SwingWorker worker = new SwingWorker () {protected String doInBackground () throws InterruptedException {return null; } protected void done () {System.out.println ("Na vlákne udalosti?:" + EventQueue.isDispatchThread ()); Tlačidlo JButton = (JButton) e.getChild (); Štítok reťazca = button.getText (); button.setText (štítok + "0"); }}; worker.execute (); }}; frame.getContentPane (). addContainerListener (kontajner); frame.add (tlačidlo, BorderLayout.CENTER); frame.setSize (200, 200); System.out.println ("Chystám sa realizovať:" + EventQueue.isDispatchThread ()); frame.setVisible (true); }}; EventQueue.invokeLater (bežec); }}

Spustite to teraz a vyššie uvedený program ukáže, že inicializácia aj kód kontajnera sú spustené vo vlákne na odoslanie udalosti:

> java GoodSwingButton Chystám sa realizovať: true Na vlákne udalosti? : pravda

Na záver

Práce navyše na vytvorení vášho používateľského rozhrania vo vlákne na odoslanie udalosti sa spočiatku môžu javiť ako zbytočné. Každý to predsa od začiatku vekov robil inak. Prečo sa teraz namáhať zmeniť? Ide o to, že sme to vždy robili zle. Aby ste zaistili správny prístup k svojim komponentom Swing, mali by ste vždy vytvoriť celé používateľské rozhranie v rámci vlákna na odoslanie udalosti, ako je to znázornené tu:

Runnable runner = new Runnable () {public void run () {// ... vytvorte si tu používateľské rozhranie ...}} EventQueue.invokeLater (runner);

Presunutie vášho inicializačného kódu do vlákna na odosielanie udalostí je jediný spôsob, ako zabezpečiť, aby vaše grafické rozhrania Swing boli bezpečné pre vlákno. Áno, zo začiatku to bude nepríjemné, ale pokrok sa zvyčajne stáva.

John Zukowski hrá s Java už viac ako 12 rokov a svoje myslenie v systémoch C a X-Windows opustil už dávno. S 10 knihami venovanými témam od Swingu po zbierky po Javu SE 6 John teraz vykonáva strategické technologické poradenstvo prostredníctvom svojej firmy JZ Ventures, Inc.

Získajte viac informácií o tejto téme

  • Získajte viac informácií o programovaní Swing a vlákne odosielania udalostí od jedného z majstrov vývoja desktopových aplikácií v Java: Chet Haase o maximalizácii Swing a Java 2D (podcast JavaWorld Java Technology Insider, august 2007).
  • „Prispôsobte program SwingWorker na zlepšenie grafických používateľských rozhraní Swing“ (Yexin Chen, JavaWorld, jún 2003) sa venuje hlbšie niektorým výzvam súvisiacim s vývojom vlákien Swing, o ktorých sa hovorí v tomto článku, a vysvetľuje, ako SwingWorker môže poskytnúť svalu na prácu okolo nich.
  • „Java a spracovanie udalostí“ (Todd Sundsted, JavaWorld, august 1996) je základom pre spracovanie udalostí okolo AWT.
  • „Zrýchlenie notifikácie poslucháča“ (Robert Hastings, JavaWorld, február 2000) predstavuje špecifikáciu JavaBeans 1.0 pre registráciu a notifikáciu udalostí.
  • „Dosiahnite vysoký výkon s vláknami, 1. časť“ (Jeff Friesen, JavaWorld, máj 2002) predstavuje vlákna Java. V 2. časti nájdete odpoveď na otázku: Prečo potrebujeme synchronizáciu?
  • „Vykonávanie úloh v vláknach“ je výňatok z JavaWorld Java súbežnosť v praxi (Brian Goetz a kol., Addison Wesley Professional, máj 2006), ktorý podporuje programovanie vlákien na základe úloh a zavádza rámec vykonávania pre správu úloh.
  • „Vlákna a Swing“ (Hans Muller a Kathy Walrath, apríl 1998) je jedným z prvých oficiálnych odkazov na vlákna Swing. Zahŕňa dnes známe (a chybné) „pravidlo jedného vlákna“.
  • Vytváranie grafického používateľského rozhrania pomocou JFC / Swing je komplexná stránka výučby Java pre programovanie grafického používateľského rozhrania Swing.
  • „Súbežnosť vo Swingu“ je výukový program k chodníku Swing, ktorý obsahuje úvod do SwingWorker trieda.
  • JSR 296: Swing Application Framework je v súčasnosti v štádiu špecifikácie. Prečítajte si tiež časť „Používanie aplikačného rámca Swing“ (John O'Conner, Sun Developer Network, júl 2007), kde sa dozviete viac o tomto ďalšom kroku vo vývoji programovania grafického používateľského rozhrania Swing.
  • Celá príručka Java AWT Reference (John Zukowski, O'Reilly, marec 1997) je k dispozícii zadarmo v online katalógu O'Reilly.
  • John's Definitive Guide to Java Swing, tretie vydanie (Apress, jún 2005) je pre verziu Java Standard Edition verzie 5.0 úplne aktualizovaný. Prečítajte si ukážkovú kapitolu z knihy priamo tu JavaWorld!
  • Navštívte výskumné centrum JavaWorld Swing / GUI, kde nájdete ďalšie články o programovaní Swing a vývoji desktopových aplikácií Java.
  • Skontrolujte tiež diskusné fóra pre vývojárov JavaWorld a otázky a odpovede týkajúce sa programovania Swing a Java pre počítače.

Tento príbeh, „Swing threading and the event-dispatch thread“, bol pôvodne publikovaný spoločnosťou JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found