Safe way to replace AWT EventQueue when starting Swing application

The various sporadic issues in the Swing app that I support appear to be caused by the way it replaces the default AWT event queue with its own version using Toolkit.getDefaultToolkit().getSystemEventQueue().push(new AEventQueue())

. See Threading and Deadlock in Swing Application . The problem described there has been resolved, but my tests (using FEST Swing) now tend to get stuck.

I suspect that the best solution would be to replace the event queue at the beginning of the application initialization, before the Swing components are created. However, there are some dependencies that make this awkward, so for now I'm trying to find a safe way to "push" the new event queue after initialization, where it's currently being done.

The two approaches I have tried are -

  • push the new queue on EDT using SwingUtilities.invokeLater()

    ;
  • click on the new queue on the main thread after initialization and after use invokeLater()

    to avoid deadlock with anything already started on the old EDT.

What I would expect after reading this StackOverflow question is that the first approach might work in Java 7, but something like the second might be required in Java 1.6. Indeed, the second works in Java 1.6, while in Java 7 both succeed, but are very slow. It might just be a FEST issue as the app itself seems to be quite responsive.

So I am pretty much forced to use the second approach, which at least works in Java 1.6, but I would like to know - if there is a safer way to implement this, since it looks like it might be vulnerable to a race condition if the event occurs in an existing queue after invokeLater

, but before creating a new queue; - if there is another approach I should use instead.

More details

The first "solution" looks like this:

    initApplication();
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Toolkit.getDefaultToolkit().getSystemEventQueue().push(new CustomEventQueue());
        }
    });

      

When compiled and executed using Java 1.6, I don't understand what it does. It seems that the thread is waiting for the lock it already has:

"AWT-EventQueue-1" prio=10 tid=0x00007f9808001000 nid=0x6628 in Object.wait() [0x00007f986aa72000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007d9961cf0> (a atlantis.gui.AEventQueue)
    at java.lang.Object.wait(Object.java:502)
    at java.awt.EventQueue.getNextEvent(EventQueue.java:490)
    - locked <0x00000007d9961cf0> (a atlantis.gui.AEventQueue)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:247)

      

The second "solution" looks like this:

    initApplication();
    try {
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                logger.debug("Waiting for AWT event queue to be empty.");
            }
        });
    } catch (InterruptedException e) {
        logger.error("Interrupted while waiting for event queue.", e);
    } catch (InvocationTargetException e) {
        logger.error("Error while waiting for event queue.",e);
    }
    Toolkit.getDefaultToolkit().getSystemEventQueue().push(new CustomEventQueue());

      

As stated above, this seems to work fine in Java 1.6, but I'm not sure if it's really safe.

I haven't figured out what's going on when using Java 7, but the main thread seems to have been weaving the method for a long time org.fest.swing.timing.Pause.pause()

, so I suspect it might be a FEST related issue.

+3


source to share


1 answer


Since I see no reason to reset the current EDT with a fresh one, my questions are

1), you got some of

  • Java deallock, outofmemory ...

  • RepaintManager exceptions,

2) basically you can

  • block the EDT current with Thread.sleep(int)

    , setVisible(false)

    for caused JComponent

    ,

  • If there is an EDT then you should use invokeLater

    , if it is inactive you can choose betweens invokeLater

    ofinvokeAndWait

code



if (EventQueue.isDispatchThread()) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            //some stuff
        }
    });
} else {
    try {
        SwingUtilities.invokeAndWait(new Runnable() {

            @Override
            public void run() {
                //some stuff
            }
        });
    } catch (InterruptedException ex) {
        Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvocationTargetException ex) {
        Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
    }
}

      

3) notification invokeAndWait

must be triggered from EDT, otherwise it was triggered EDT exceptions

with deactivation of EDT current

4) if there is no active EDT then there is no reason for push()

something toEventQueue

5) simple test code for all of the above.

import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class IsThereEDT {

    private ScheduledExecutorService scheduler;
    private AccurateScheduledRunnable periodic;
    private ScheduledFuture<?> periodicMonitor;
    private int taskPeriod = 30;
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    private Date dateRun;
    private JFrame frame1 = new JFrame("Frame 1");

    public IsThereEDT() {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        periodic = new AccurateScheduledRunnable() {

            private final int ALLOWED_TARDINESS = 200;
            private int countRun = 0;
            private int countCalled = 0;
            private int maxCalled = 10;

            @Override
            public void run() {
                countCalled++;
                if (countCalled < maxCalled) {
                    if (countCalled % 3 == 0) {
                        /*if (EventQueue.isDispatchThread()) {
                            SwingUtilities.invokeLater(new Runnable() {

                                @Override
                                public void run() {
                                    //some stuff
                                }
                            });
                        } else {
                            try {
                                SwingUtilities.invokeAndWait(new Runnable() {

                                    @Override
                                    public void run() {
                                        //some stuff
                                    }
                                });
                            } catch (InterruptedException ex) {
                                Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
                            } catch (InvocationTargetException ex) {
                                Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }*/
                        SwingUtilities.invokeLater(new Runnable() {

                            @Override
                            public void run() {
                                System.out.println("Push a new event to EDT");
                                frame1.repaint();
                                isThereReallyEDT();
                            }
                        });
                    } else {
                        if (this.getExecutionTime() < ALLOWED_TARDINESS) {
                            countRun++;
                            isThereReallyEDT(); // non on EDT
                        }
                    }
                } else {
                    System.out.println("Terminating this madness");
                    System.exit(0);
                }
            }
        };
        periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.SECONDS);
        periodic.setThreadMonitor(periodicMonitor);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                isThereReallyEDT();
                frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame1.getContentPane().add(new JLabel("Hello in frame 1"));
                frame1.pack();
                frame1.setLocation(100, 100);
                frame1.setVisible(true);
            }
        });
        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
            Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
        }
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame2 = new JFrame("Frame 2");
                frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame2.getContentPane().add(new JLabel("Hello in frame 2"));
                frame2.pack();
                frame2.setLocation(200, 200);
                frame2.setVisible(true);
                isThereReallyEDT();
            }
        });
    }

    private void isThereReallyEDT() {
        dateRun = new java.util.Date();
        System.out.println("                         Time at : " + sdf.format(dateRun));
        if (EventQueue.isDispatchThread()) {
            System.out.println("EventQueue.isDispatchThread");
        } else {
            System.out.println("There isn't Live EventQueue.isDispatchThread, why any reason for that ");
        }
        if (SwingUtilities.isEventDispatchThread()) {
            System.out.println("SwingUtilities.isEventDispatchThread");
        } else {
            System.out.println("There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        IsThereEDT isdt = new IsThereEDT();
    }
}

abstract class AccurateScheduledRunnable implements Runnable {

    private ScheduledFuture<?> thisThreadsMonitor;

    public void setThreadMonitor(ScheduledFuture<?> monitor) {
        this.thisThreadsMonitor = monitor;
    }

    protected long getExecutionTime() {
        long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS);
        return delay;
    }
}

      

+3


source







All Articles