Programmering

Svingtråd og hendelsesutsendelsetråden

Forrige 1 2 3 4 5 Side 5 Side 5 av 5

Å holde svingtråden trygg

Det siste trinnet i å lage en Swing GUI er å starte den. Den riktige måten å starte en Swing GUI i dag er forskjellig fra Suns opprinnelig foreskrevne tilnærming. Her er sitatet fra Sun-dokumentasjonen igjen:

Når en Swing-komponent er realisert, bør all kode som kan påvirke eller avhenge av tilstanden til den komponenten, kjøres i hendelsesutsendelsetråden.

Kast disse instruksjonene ut av vinduet, for rundt JSE 1.5 ble alle eksemplene på Suns side endret. Siden den tiden har det vært et lite kjent faktum at du skal alltid få tilgang til svingkomponenter på hendelsen-utsendelsetråden for å sikre deres trådsikkerhet / tilgang med en tråd. Årsaken til endringen er enkel: mens programmet ditt kan få tilgang til en Swing-komponent av hendelsen-utsendelsetråden før komponenten blir realisert, kan initialiseringen av Swing UI utløse noe å kjøre på hendelsen-utsendelsetråden etterpå, fordi komponent / brukergrensesnitt forventer å kjøre alt på hendelsen-utsendelsetråden. Å ha GUI-komponenter kjørt på forskjellige tråder, bryter Swings enkelttrådede programmeringsmodell.

Programmet i Listing 5 er ikke helt realistisk, men det tjener til å gjøre mitt poeng.

Oppføring 5. Få tilgang til Swing-komponenttilstand fra flere tråder

importer java.awt. *; importer java.awt.event. *; import javax.swing. *; offentlig klasse BadSwingButton {public static void main (String args []) {JFrame frame = new JFrame ("Title"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); JButton-knapp = ny JButton ("Trykk her"); ContainerListener container = new ContainerAdapter () {public void componentAdded (final ContainerEvent e) {SwingWorker worker = new SwingWorker () {protected String doInBackground () throw InterruptedException {Thread.sleep (250); return null; } beskyttet tomrom gjort () {System.out.println ("På hendelsestråden?:" + EventQueue.isDispatchThread ()); JButton-knapp = (JButton) e.getChild (); Strengetikett = button.getText (); button.setText (etikett + "0"); }}; arbeider. utfør (); }}; frame.getContentPane (). addContainerListener (container); frame.add (knapp, BorderLayout.CENTER); frame.setSize (200, 200); prøv {Thread.sleep (500); } fange (InterruptedException e) {} System.out.println ("Jeg er i ferd med å bli realisert:" + EventQueue.isDispatchThread ()); frame.setVisible (true); }}

Legg merke til at utgangen viser noe kode som kjører på hovedtråden før brukergrensesnittet blir realisert. Dette betyr at initialiseringskoden kjører på en tråd, mens annen brukergrensesnittkode kjører på hendelsesutsendelsetråden, som bryter Swings enkelttrådede tilgangsmodell:

> java BadSwingButton På hendelsestråden? : sant jeg er i ferd med å bli realisert: falsk

Programmet i Listing 5 oppdaterer knappens etikett fra beholderen til containeren når knappen legges til beholderen. For å gjøre scenariet mer realistisk, forestill deg et brukergrensesnitt som "teller" etiketter i det og bruker tellingen som teksten i kanttittelen. Naturligvis vil det trenge å oppdatere grensens titteltekst i hendelsesutsendelsetråden. For å gjøre ting enkelt, oppdaterer programmet bare etiketten på en knapp. Selv om det ikke er realistisk i funksjon, viser dette programmet problemet med hver Swing-program som er skrevet siden begynnelsen av Swings tid. (Eller i det minste alle de som fulgte den anbefalte threading-modellen som ble funnet i javadocs og online tutorials fra Sun Microsystems, og til og med i mine helt egne tidlige utgaver av Swing-programmeringsbøker.)

Svingtråd gjort riktig

Måten å få Swing-tråden riktig på er å glemme Suns originale dictum. Ikke bekymre deg for om en komponent er realisert eller ikke. Ikke bry deg med å prøve å avgjøre om det er trygt å få tilgang til noe utenfor hendelsen-utsendelsetråden. Det er det aldri. Opprett i stedet hele brukergrensesnittet på hendelsen-utsendelsetråden. Hvis du plasserer hele brukergrensesnittopprettingen i en EventQueue.invokeLater () alle tilganger under initialiseringen er garantert å bli gjort i hendelsesutsendelsetråden. Det er så enkelt.

Oppføring 6. Alt på plass

importer java.awt. *; importer java.awt.event. *; import javax.swing. *; offentlig klasse 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); JButton-knapp = ny JButton ("Trykk her"); ContainerListener container = new ContainerAdapter () {public void componentAdded (final ContainerEvent e) {SwingWorker worker = new SwingWorker () {protected String doInBackground () throw InterruptedException {return null; } beskyttet tomrom gjort () {System.out.println ("På hendelsestråden?:" + EventQueue.isDispatchThread ()); JButton-knapp = (JButton) e.getChild (); Strengetikett = button.getText (); button.setText (etikett + "0"); }}; arbeider. utfør (); }}; frame.getContentPane (). addContainerListener (container); frame.add (knapp, BorderLayout.CENTER); frame.setSize (200, 200); System.out.println ("Jeg er i ferd med å bli realisert:" + EventQueue.isDispatchThread ()); frame.setVisible (true); }}; EventQueue.invokeLater (løper); }}

Kjør det nå, og programmet ovenfor viser at både initialisering og containerkode kjører på hendelsesutsendelsetråden:

> java GoodSwingButton Jeg er i ferd med å bli realisert: sant På begivenhetstråden? : sant

For å konkludere

Det ekstra arbeidet med å lage brukergrensesnittet ditt i hendelsesutsendelsetråden, kan virke unødvendig i begynnelsen. Alle har tross alt gjort det den andre veien siden begynnelsen av tiden. Hvorfor gidder å endre nå? Saken er at vi alltid har gjort det galt. For å sikre at Swing-komponentene dine er riktig tilgjengelige, bør du alltid opprette hele brukergrensesnittet i tråden for hendelsesutsendelse, som vist her:

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

Å flytte initialiseringskoden til hendelsen-utsendingstråden er den eneste måten å sikre at Swing GUI-ene dine er sikre. Ja, det vil føles vanskelig i begynnelsen, men fremgang gjør det vanligvis.

John Zukowski har spilt med Java i godt over 12 år nå, etter å ha forlatt C- og X-Windows-tankegangen for lenge siden. Med ti bøker om temaer fra Swing til samlinger til Java SE 6, gjør John nå strategisk teknologirådgivning gjennom sin virksomhet, JZ Ventures, Inc.

Lær mer om dette emnet

  • Lær mer om Swing-programmering og hendelsesutsendelsetråden fra en av mesterne i Java desktop-utvikling: Chet Haase om å maksimere Swing og Java 2D (JavaWorld Java Technology Insider podcast, august 2007).
  • "Tilpass SwingWorker for å forbedre Swing GUIs" (Yexin Chen, JavaWorld, juni 2003) graver dypere inn i noen av Swing-threading-utfordringene som er diskutert i denne artikkelen og forklarer hvordan en tilpasset SwingWorker kan gi muskelen å jobbe rundt dem.
  • "Java and event handling" (Todd Sundsted, JavaWorld, august 1996) er en primer på begivenhetshåndtering rundt AWT.
  • "Speed ​​up listener notification" (Robert Hastings, JavaWorld, februar 2000) introduserer JavaBeans 1.0 spesifikasjonen for registrering og varsling av hendelser.
  • "Oppnå sterk ytelse med tråder, del 1" (Jeff Friesen, JavaWorld, mai 2002) introduserer Java-tråder. Se del 2 for svar på spørsmålet: Hvorfor trenger vi synkronisering?
  • "Å utføre oppgaver i tråder" er et JavaWorld-utdrag fra Java samtidighet i praksis (Brian Goetz, et al., Addison Wesley Professional, mai 2006) som oppmuntrer til oppgavebasert trådprogrammering og introduserer et utførelsesrammeverk for oppgavebehandling.
  • "Threads and Swing" (Hans Muller og Kathy Walrath, april 1998) er en av de tidligste offisielle referansene for Swing threading. Den inkluderer den nå berømte (og feilaktige) "single-thread rule."
  • Å lage en GUI med JFC / Swing er den omfattende Java Tutorial-siden for Swing GUI-programmering.
  • "Concurrency in Swing" er en opplæring om Swing trail som inkluderer en introduksjon til SwingWorker klasse.
  • JSR 296: Swing Application Framework er for tiden en spesifikasjon pågår. Se også "Bruke Swing Application Framework" (John O'Conner, Sun Developer Network, juli 2007) for å lære mer om dette neste trinnet i utviklingen av Swing GUI-programmering.
  • Hele Java AWT-referansen (John Zukowski, O'Reilly, mars 1997) er tilgjengelig gratis fra O'Reilly Online Catalog.
  • Johns definitive guide til Java Swing, tredje utgave (Apress, juni 2005) er fullstendig oppdatert for Java Standard Edition versjon 5.0. Les et forhåndsvisningskapittel fra boka her på JavaWorld!
  • Besøk JavaWorld Swing / GUI forskningssenter for flere artikler om Swing programmering og Java desktop utvikling.
  • Sjekk også JavaWorld-utviklerforaene for diskusjoner og spørsmål knyttet til Swing og Java desktop programmering.

Denne historien, "Swing threading and the event-dispatch thread" ble opprinnelig utgitt av JavaWorld.

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