Programování

Swing threading a vlákno pro odesílání událostí

Předchozí 1 2 3 4 5 Strana 5 Stránka 5 z 5

Udržování bezpečného vlákna Swing

Posledním krokem při vytváření Swing GUI je jeho spuštění. Správný způsob spuštění Swing GUI se dnes liší od původně předepsaného přístupu společnosti Sun. Zde je citát z dokumentace společnosti Sun:

Po realizaci komponenty Swing by měl být ve vlákně pro odesílání událostí spuštěn veškerý kód, který by mohl ovlivnit nebo záviset na stavu této komponenty.

Nyní tyto pokyny vyhoďte z okna, protože kolem, když vyšlo JSE 1.5, se všechny příklady na stránkách Sunu změnily. Od té doby to byla málo známá skutečnost, kterou byste měli mít vždy přistupovat ke komponentám Swing ve vlákně pro odesílání událostí, aby byla zajištěna jejich bezpečnost vlákna / přístup s jedním závitem. Důvod této změny je jednoduchý: zatímco váš program může přistupovat ke komponentě Swing mimo vlákno pro odesílání událostí před tím, než je komponenta realizována, inicializace uživatelského rozhraní Swing by mohla spustit něco, co by později běželo na vlákně pro událost, protože komponenta / uživatelské rozhraní očekává spuštění všeho ve vlákně pro odesílání událostí. Spuštění komponent GUI na různých vláknech přeruší programovací model Swing s jedním závitem.

Program ve Výpisu 5 není úplně realistický, ale slouží k mé poznámce.

Výpis 5. Přístup ke stavu komponenty Swing z více vláken

importovat java.awt. *; importovat java.awt.event. *; importovat javax.swing. *; public class BadSwingButton {public static void main (String args []) {JFrame frame = new JFrame ("Title"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); Tlačítko JButton = nové JButton („Stiskněte zde“); ContainerListener container = new ContainerAdapter () {public void componentAdded (final ContainerEvent e) {SwingWorker worker = new SwingWorker () {protected String doInBackground () throws InterruptedException {Thread.sleep (250); vrátit null; } protected void done () {System.out.println ("Na vlákně události?:" + EventQueue.isDispatchThread ()); Tlačítko JButton = (JButton) e.getChild (); Řetězcový štítek = button.getText (); button.setText (štítek + "0"); }}; worker.execute (); }}; frame.getContentPane (). addContainerListener (kontejner); frame.add (tlačítko, BorderLayout.CENTER); frame.setSize (200, 200); zkuste {Thread.sleep (500); } catch (InterruptedException e) {} System.out.println ("Chystám se být realizován:" + EventQueue.isDispatchThread ()); frame.setVisible (true); }}

Všimněte si, že výstup zobrazuje nějaký kód běžící na hlavním vlákně před realizací uživatelského rozhraní. To znamená, že inicializační kód běží na jednom vlákně, zatímco jiný kód uživatelského rozhraní běží na vláknu pro odesílání událostí, což rozbije přístupový model Swing s jedním vláknem:

> java BadSwingButton Na vlákně události? : true Chystám se být realizován: false

Program v seznamu 5 aktualizuje štítek tlačítka od posluchače kontejneru, když je tlačítko přidáno do kontejneru. Aby byl scénář realističtější, představte si uživatelské rozhraní, které v něm „spočítá“ štítky a použije počet jako text v názvu ohraničení. Přirozeně by bylo potřeba aktualizovat text nadpisu ohraničení ve vlákně pro odesílání událostí. Pro zjednodušení program pouze aktualizuje štítek jednoho tlačítka. I když to není realistické, tento program ukazuje problém s každý Swing program, který byl napsán od začátku Swingovy doby. (Nebo alespoň všechny ty, které následovaly doporučený model vláken nalezený v javadocs a online tutoriálech od Sun Microsystems a dokonce i v mých vlastních raných vydáních programovacích knih Swing.)

Swing závitování hotovo správně

Způsob, jak správně navléknout Swing, je zapomenout na původní Sunovo výrok. Nedělejte si starosti s tím, zda je součást realizována nebo ne. Neobtěžujte se snahou zjistit, zda je bezpečné přistupovat k něčemu mimo podproces odesílání událostí. Nikdy to tak není. Místo toho vytvořte celé uživatelské rozhraní ve vlákně pro odesílání událostí. Pokud umístíte celé volání vytvoření uživatelského rozhraní dovnitř EventQueue.invokeLater () je zaručeno, že všechny přístupy během inicializace budou provedeny v podprocesu odeslání události. Je to tak jednoduché.

Výpis 6. Všechno na svém místě

importovat java.awt. *; importovat java.awt.event. *; importovat 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čítko JButton = nové JButton („Stiskněte zde“); 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ákně události?:" + EventQueue.isDispatchThread ()); Tlačítko JButton = (JButton) e.getChild (); Řetězcový štítek = button.getText (); button.setText (štítek + "0"); }}; worker.execute (); }}; frame.getContentPane (). addContainerListener (kontejner); frame.add (tlačítko, BorderLayout.CENTER); frame.setSize (200, 200); System.out.println ("Chystám se být realizován:" + EventQueue.isDispatchThread ()); frame.setVisible (true); }}; EventQueue.invokeLater (běžec); }}

Spusťte jej hned teď a výše uvedený program ukáže, že inicializační i kontejnerový kód běží na podprocesu odeslání události:

> java GoodSwingButton Chystám se být realizován: true Na vlákně události? : skutečný

Závěrem

Práce navíc k vytvoření vašeho uživatelského rozhraní ve vlákně pro odesílání událostí se na první pohled může zdát zbytečná. Všichni to koneckonců od začátku věků dělají jinak. Proč se teď obtěžovat změnit? Jde o to, že jsme to vždy dělali špatně. Abyste zajistili správný přístup ke svým komponentám Swing, měli byste vždy vytvořit celé uživatelské rozhraní v podprocesu odeslání události, jak je znázorněno zde:

Runnable runner = new Runnable () {public void run () {// ... create UI here ...}} EventQueue.invokeLater (runner);

Přesunutí inicializačního kódu do vlákna pro odesílání událostí je jediný způsob, jak zajistit, aby vaše grafická rozhraní Swing byla bezpečná pro vlákna. Ano, zpočátku to bude nepříjemné, ale pokrok obvykle ano.

John Zukowski hraje s Javou již více než 12 let a už dávno opustil své myšlení v C a X-Windows. S 10 knihami o tématech od Swingu po sbírky až po Java SE 6 nyní John provádí strategické technologické poradenství prostřednictvím svého podnikání, JZ Ventures, Inc.

Další informace o tomto tématu

  • Další informace o programování Swing a podprocesu odesílání událostí od jednoho z mistrů vývoje desktopů Java: Chet Haase o maximalizaci Swing a Java 2D (podcast JavaWorld Java Technology Insider, srpen 2007).
  • „Přizpůsobte SwingWorker za účelem zlepšení grafických uživatelských rozhraní Swing“ (Yexin Chen, JavaWorld, červen 2003) se hlouběji věnuje některým výzvám Swing threading popsaným v tomto článku a vysvětluje, SwingWorker může poskytnout svalu pro práci kolem nich.
  • „Java a zpracování událostí“ (Todd Sundsted, JavaWorld, srpen 1996) je základem pro zpracování událostí kolem AWT.
  • „Zrychlete upozornění posluchače“ (Robert Hastings, JavaWorld, únor 2000) zavádí specifikaci JavaBeans 1.0 pro registraci a oznámení událostí.
  • „Dosáhněte vysokého výkonu pomocí vláken, část 1“ (Jeff Friesen, JavaWorld, květen 2002) představuje vlákna Java. V části 2 najdete odpověď na otázku: Proč potřebujeme synchronizaci?
  • „Spouštění úkolů v podprocesech“ je výňatek z JavaWorld Souběžnost Java v praxi (Brian Goetz a kol., Addison Wesley Professional, květen 2006), který podporuje programování podprocesů na základě úkolů a zavádí rámec provádění pro správu úkolů.
  • „Threads and Swing“ (Hans Muller a Kathy Walrath, duben 1998) je jednou z prvních oficiálních referencí pro Swing threading. Zahrnuje nyní známé (a chybné) „pravidlo jednoho vlákna“.
  • Vytvoření grafického uživatelského rozhraní pomocí JFC / Swing je komplexní stránka výukového programu Java pro programování grafického uživatelského rozhraní Swing.
  • "Souběžnost ve Swingu" je výukový program na Swing Trail, který obsahuje úvod do SwingWorker třída.
  • JSR 296: Swing Application Framework je v současné době specifikace probíhá. Další informace o tomto dalším kroku ve vývoji programování grafického uživatelského rozhraní Swing naleznete také v části „Používání aplikačního rámce Swing“ (John O'Conner, Sun Developer Network, červenec 2007).
  • Celá reference Java AWT (John Zukowski, O'Reilly, březen 1997) je k dispozici zdarma v online katalogu O'Reilly.
  • John's Definitive Guide to Java Swing, Third Edition (Apress, červen 2005) je pro verzi Java Standard Edition verze 5.0 zcela aktualizován. Zde si přečtěte kapitolu z knihy JavaWorld!
  • Navštivte výzkumné centrum JavaWorld Swing / GUI, kde najdete další články o programování Swing a vývoji desktopů Java.
  • Podívejte se také na fóra vývojářů JavaWorld, kde najdete diskuse a otázky a odpovědi týkající se programování Swing a Java pro stolní počítače.

Tento příběh, „Swing threading and the event-dispatch thread“, původně publikoval JavaWorld.

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