Qual è il vantaggio del metodo "SwingUtilities.invokeLater ()"?

5

Per il seguente esempio di programma GUI utilizzando javax.swing,

public class UnResponsiveUI extends JFrame{


    private boolean stop = false;
    private JTextField tfCount;
    private int count = 1;

    /* Constructor to setup the GUI components */
    public UnResponsiveUI(){
        Container cp = this.getContentPane();
        cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
        cp.add(new JLabel("Counter"));
        tfCount = new JTextField(count + "", 10);
        tfCount.setEditable(false);
        cp.add(tfCount);

        JButton btnStart = new JButton("Start Counting");
        cp.add(btnStart);
        btnStart.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                stop = false;
                for (int i = 0; i < 100000; ++i) {
                   if (stop) break;  // check if STOP button has been pushed,
                                     //  which changes the stop flag to true
                   tfCount.setText(count + "");
                   ++count;
                }
            }
        });

        JButton btnStop = new JButton("Stop Counting");
        cp.add(btnStop);
        btnStop.addActionListener(new ActionListener(){
            @Override
             public void actionPerformed(ActionEvent evt) {
                stop = true;  // set the stop flag
             }
        });

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Counter");
        setSize(300, 120);
        setVisible(true);
    }

    public static void main(String[] args){
        /*SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new UnResponsiveUI();  // Let the constructor do the job
             }
        });*/

        /* new UnResponsiveUI(); */ 

        System.out.println("main thread exits");

    }

}

Nel primo scenario, dopo aver eseguito il debug del costruttore richiamato da main () come new UnResponsiveUI(); , di seguito viene riportata l'osservazione del numero di thread avviati:

1. The main() method starts in the "main" thread.

2. A new thread "AWT-Windows" (Daemon thread) is started when we step-into the constructor "new UnresponsiveUI()" (because of the "extends JFrame").

3. After executing "setVisible(true)", another two threads are created - "AWT-Shutdown" and "AWT-EventQueue-0" (i.e., the EDT).

4. The "main" thread exits after the main() method completes. A new thread called "DestroyJavaVM" is created.

5. At this point, there are 4 threads running - "AWT-Windows", "AWT-Shutdown" and "AWT-EventQueue-0 (EDT)" and "DestroyJavaVM".

6. Clicking the START button invokes the actionPerformed() in the EDT.

Nel secondo scenario, dopo il debug del costruttore da main () invocato come,

SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new UnResponsiveUI();  // Let the constructor do the job
             }
        });

Segue l'osservazione per il numero di thread che vengono lanciati ma in istanze temporali diverse:

1. The main() method is started in the "main" thread.

2. The JRE's windowing subsystem, via SwingUtilities.invokeLater(), starts 3 threads at a time: "AWT-Windows" (daemon thread), "AWT-Shutdown" and "AWT-EventQueue-0". The "AWT-EventQueue-0" is known as the Event-Dispatching Thread (EDT), which is the one and only thread responsible for handling all the events (such as clicking of buttons) and refreshing the display to ensure thread safety in GUI operations and manipulating GUI components.

3. Then we step-into the constructor UnresponsiveUI()to run on the Event-Dispatching thread (created via invokeLater()), after all the existing events have been processed.

4. The "main" thread exits after the main() method completes.

5. A new thread called "DestroyJavaVM" is created.

Quindi, in due scenari sopra, il numero totale di thread da creare è lo stesso, ma in istanze temporali diverse ed eseguire il costruttore della GUI sullo stesso EDT.

Da questa query , ho appreso che: "Se non hai usato invokeLater e invece hai appena aggiornato l'ui direttamente potresti avere una race condition e potrebbe verificarsi un comportamento indefinito. "

La mia domanda:

Qual è il vantaggio dell'utilizzo del metodo SwingUtilities.invokeLater() ? Perché in un secondo scenario, l'avvio di EDT prima dell'ingresso nel costruttore non ha aggiunto alcun valore.

    
posta overexchange 01.12.2014 - 14:10
fonte

1 risposta

2

L'uso di SwingUtilities.invokeLater () non è semplicemente vantaggioso, è essenziale, ma è necessario capire perché è necessario comprendere il modello di threading di Swing.

Gli aggiornamenti alla GUI, tramite Swing, devono avvenire sul thread di invio eventi (EDT) e il codice che fa qualsiasi altra cosa (ad esempio l'accesso ad alcune risorse come un database) dovrebbe utilizzare uno o più altri thread.

invokeLater () abilita questi altri thread ad aggiornare la GUI con i loro risultati, nell'EDT, ad es. mostrando il risultato di una query del database.

invokeLater () viene chiamato in questo modo per rendere ovvio che è asincrono nel richiamare l'oggetto Runnable che gli viene dato, poiché l'EDT potrebbe essere occupato al momento - non è che tu vuoi esplicitamente succederà più tardi.

    
risposta data 02.01.2015 - 19:57
fonte

Leggi altre domande sui tag