Java Thread Programming 1.9.1 – Threads and Swing

來源:互聯網
上載者:User
Why Isn’t the Swing Toolkit Multithread-Safe?  After Swing components have been displayed on the screen, they should only be operated on by the event-handling thread. The event-handling thread (or just event thread) is started automatically by the Java VM when an application has a graphical interface. The event thread calls methods like paint() on Component , actionPerformed() on ActionListener , and all of the other event-handling methods. 當Swing組件顯示在螢幕上之後,只應該被訊息處理線程操作。當應用程式具有圖形介面時,java虛擬機器會自動建立訊息處理線程,負責調用Component的paint()方法,ActionListener的actionPerformed()方法等等訊息處理方法。 Most of the time, modifications to Swing components are done in the event-handling methods. Because the event thread calls these methods, it is perfectly safe to directly change components in event-handling code. SimpleEvent (see Listing 9.1) shows safe Swing code. /* * Created on 2005-7-17 * * Java Thread Programming - Paul Hyde  * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 *  */package org.tju.msnrl.jonathan.thread.chapter9; import java.awt.*;import java.awt.event.*;import javax.swing.*; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo *      blog.yesky.net/jonathanundersun *  * Enjoy Life with Sun! *  */public class SimpleEvent {    private static void print(String msg){        String temp = Thread.currentThread().getName();        System.out.println(temp + " - " + msg);    }     public static void main(String[] args) {        final JLabel lb = new JLabel("_____");        JButton bt = new JButton("Click here!");        JPanel pn = new JPanel(new FlowLayout());        pn.add(lb);        pn.add(bt);                bt. addActionListener(          new ActionListener(){              public void actionPerformed(ActionEvent e){                  print("do action ... ");                  lb.setText("Clicked!");              }          }        );                JFrame fm = new JFrame("simple event");        fm.setContentPane(pn);        fm.setSize(300,100);        fm.setVisible(true);            }} 控制台輸出結果:AWT-EventQueue-0 - do action ...  表明訊息線程在做處理  Using SwingUtilities.invokeAndWait()  The developers of the Swing toolkit realized that there would be times when an external thread would need to make changes to Swing components. They created a mechanism that puts a reference to a chunk of code on the event queue. When the event thread gets to this code block, it executes the code. This way, the GUI can be changed inside this block of code by the event thread. 有時候外部線程(非訊息處理線程),需要操作Swing組件。可以把一些代碼放到訊息佇列上,由訊息線程執行,這樣GUI就可以由外部線程的代碼塊來改變(仍舊通過調用訊息線程)。 The SwingUtilities class has a static invokeAndWait() method available to use to put references to blocks of code onto the event queue: public static void invokeAndWait(Runnable target)        throws InterruptedException,               InvocationTargetException An InterruptedException is thrown if the thread that called invokeAndWait() is interrupted before the block of code referred to by target completes. An InvocationTargetException (a class in the java.lang.reflect package) is thrown if an uncaught exception is thrown by the code inside run(). 如果在target完成之前,調用invokeAndWait()的線程interrupted,則會拋出InterruptedException如果run()方法內有未捕獲的異常,會拋出InvocationTargetException()異常(屬於java.lang.reflect包) A new thread is not created when Runnable is used with SwingUtilities.invokeAndWait(). The event thread will end up calling the run() method of the Runnable when its turn comes up on the event queue. 注意:雖然這個地方建立了一個Runnable對象,但並不建立新線程來執行它,而是訊息線程執行。 /* * Created on 2005-7-17 * * Java Thread Programming - Paul Hyde  * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 *  */package org.tju.msnrl.jonathan.thread.chapter9; import java.awt.*;//import java.awt.event.*;//don't need this packageimport javax.swing.*;import java.lang.reflect.*;//just for 'InvocationTargetException' /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo *      blog.yesky.net/jonathanundersun *  * Enjoy Life with Sun! *  */public class InvokeAndWait {    private static void print(String msg){        String temp = Thread.currentThread().getName();        System.out.println(temp + " - " + msg);    }     public static void main(String[] args) {        final JLabel lb = new JLabel("_____");        JButton bt = new JButton("Click here!");        JPanel pn = new JPanel(new FlowLayout());        pn.add(lb);        pn.add(bt);                JFrame fm = new JFrame("simple event");        fm.setContentPane(pn);        fm.setSize(300,100);        fm.setVisible(true);                /*        lb.setText("Clicked");        lb.repaint();        */                /*三秒後自動更改label*/        try{            Thread.sleep(3000);            print("thread sleep 3secs");                        print("create a code block to run by event-thread");            Runnable runA = new Runnable(){              public void run()  {                  print("do change label ...");                  lb.setText("Clicked");              }            };                        print("begin to run invokeandwait()");            /*交由訊息線程處理*/            SwingUtilities.invokeAndWait(runA);            print("end from invokeandwait()");                    }catch(InterruptedException e1){            e1.printStackTrace();        }catch(InvocationTargetException e2){            e2.printStackTrace();        }            }} 控制台輸出結果:main - thread sleep 3secsmain - create a code block to run by event-threadmain - begin to run invokeandwait()AWT-EventQueue-0 - do change label ...main - end from invokeandwait() Do not call SwingUtilities.invokeAndWait() from the event thread. Doing so causes an instance of Error to be thrown. Even if this call were allowed, it would put the event thread into a deadlocked state. The event thread does not need the services of invokeAndWait() because it can make the changes directly. 不要在訊息線程內調用SwingUtilities.invokeAndWait(),會拋出一個錯誤,並且會造成訊息線程思索。訊息線程本身就可以直接改變GUI,根本不需要調用invokeAndWait()。  Using SwingUtilities.invokeLater()  The SwingUtilities class has another static method available to use to put references to blocks of code onto the event queue: public static void invokeLater(Runnable target) The SwingUtilities.invokeLater() method works like SwingUtilities.invokeAndWait() except for the fact that it puts the request on the event queue and returns right away. The invokeLater() method does not wait for the block of code inside the Runnable referred to by target to execute. This allows the thread that posted the request to move on to other activities. invokeLater()和invokeAndWait()唯一不同之處在於:invokeLater()立刻返回的,不等待run代碼執行完成。並且此方法不上拋任何異常,需要及時在target的run內部捕獲可能的異常。 Just as with invokeAndWait(), a new thread is not created when Runnable is used with SwingUtilities.invokeLater(). 同樣,執行此方法並不建立新線程。 /* * Created on 2005-7-17 * * Java Thread Programming - Paul Hyde  * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 *  */package org.tju.msnrl.jonathan.thread.chapter9; import java.awt.*;//import java.awt.event.*;//don't need this packageimport javax.swing.*;//import java.lang.reflect.*;//just for 'InvocationTargetException' /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo *      blog.yesky.net/jonathanundersun *  * Enjoy Life with Sun! *  */public class InvokeLater {    private static void print(String msg){        String temp = Thread.currentThread().getName();        System.out.println(temp + " - " + msg);    }     public static void main(String[] args) {        final JLabel lb = new JLabel("_____");        JButton bt = new JButton("Click here!");        JPanel pn = new JPanel(new FlowLayout());        pn.add(lb);        pn.add(bt);                JFrame fm = new JFrame("simple event");        fm.setContentPane(pn);        fm.setSize(300,100);        fm.setVisible(true);                /*        lb.setText("Clicked");        lb.repaint();        */                /*暫停三秒鐘*/        try{            Thread.sleep(3000);            print("thread sleep 3secs");           }catch(InterruptedException e1){            e1.printStackTrace();        }                print("create block to run by invokelater()");                Runnable runA = new Runnable(){          public void run(){//需要捕獲可能的異常              try{                  Thread.sleep(100);                  print("set text to label");                  lb.setText("clicked!");              }catch(Exception e){                  e.printStackTrace();              }          }        };                print("beigin invokeLater() ... ");        SwingUtilities.invokeLater(runA);//此方法立刻返回        print("end from invokeLater() ...");            }} 控制台輸出結果:main - thread sleep 3secsmain - create block to run by invokelater()main - beigin invokeLater() ... main - end from invokeLater() ...AWT-EventQueue-0 - set text to label Unlike SwingUtilities.invokeAndWait(), the event thread is permitted to call SwingUtilities.invokeLater(). However, there isn’t any value to doing so because the event thread can change the components directly.  Using SwingUtilities.isEventDispatchThread()  public static boolean isEventDispatchThread() This static method returns true if the thread that invokes it is the event thread, and returns false if it is not. 此方法測試調用此方法的線程是否是訊息線程,如果是,返回true,反之,返回false。 if ( SwingUtilities.isEventDispatchThread() == false ) {throw new RuntimeException(        “only the event thread should invoke this method”);}  When invokeAndWait() and invokeLater() Are Not Needed  It is not always necessary to use invokeAndWait() and invokeLater() to interact with Swing components. Any thread can safely interact with the components before they have been added to a visible container. You have seen this already in the examples: The main thread constructs the GUI and then invokes setVisible(). After the components have been drawn to the screen, only the event thread should make further changes to their appearance. 不是必須使用invokeAndWait()方法和invokeLater()方法來和Swing組件互動的。當組件被加到個可見的容器之前,任何線程都可以安全地和其互動。main線程初始化GUI,然後調用setVisible(),當組件顯示在螢幕上之後,應該只由訊息線程來改變其外觀。 There are a couple of exceptions to this restriction. The adding and removing of event listeners can safely be done by any thread at any time. Also, any thread can invoke the repaint() method. The repaint() method has always worked asynchronously to put a repaint request onto the event queue. And finally, any method that explicitly indicates that it does not have to be called by the event thread is safe. The API documentation for the setText() method of JTextComponent explicitly states that setText() can be safely called by any thread. The setText() method is inherited by JTextField (a subclass of JTextComponent), so any thread can safely invoke setText() on a JTextField component at any time.  還有一些特例,任何線程隨時都可以添加或刪除訊息監聽器。任何線程都能夠調用repaint()方法,此方法非同步將repaint請求放到訊息佇列。並且,任何顯式申明為安全執行緒可以被任何線程調用的方法都是安全的,可以不通過訊息線程來調用。就像前面幾個例子中的setText()方法,在JTextComponet中說明:“This method is thread safe, although most Swing methods are not. Please see Threads and Swing for more information”,任何線程都可以直接調用,就可以更改控制面板,不需要調用repaint(),不需要invokeAndWait()等等交由訊息線程處理。   If you aren’t sure whether a particular method on a Swing component can be invoked by any thread, use the invokeAndWait() or invokeLater() mechanism to be safe.
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.