views:

77

answers:

1

I have the following problem. My J2ME app goes totally dead. I though it was a deadlock, but using NetBeans' built-in functionality, it couldn't find such.

After some time however, it started throwing out the following messages in the console:

8242276 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242284 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242292 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242340 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242540 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242628 - CORE - CRITICAL - 1 - **event queue 3 full, dropping event
8242636 - CORE - CRITICAL - 1 - **event queue 3 full, dropping event
8242644 - CORE - CRITICAL - 1 - **event queue 3 full, dropping event

And so forth.

Any ideas as to what might be the case if it is not deadlock (at leats NetBeans says so) would be highly appreciated.

Thanks!

+2  A: 

When you use AWT or Swing, there is a special thread running in the background, called the EventQueue. When you add a listener to a component (such as an ActionListener to a JButton) and the event listener method (such as actionPerformed) the method is executed on the EventQueue thread. You can choose to execute something on the EventQueue thread when the current thread isn't the EventQueue thread by running

EventQueue.invokeLater(new Runnable(){ //this could also be SwingUtilities.invokeLater() instead
    public void run(){
        ...
    }
});

This is great. The problem comes when you have a an event over and over and over. When this happens, the EventQueue thread can't execute code for the previous event fast enough to execute code for the next event. So it sticks the event into a queue while it waits for the current event-handler to finish. This might happen when you do a big operation, such as reading from a file, on the EventQueue thread. For example:

ActionListener l = new ActionListener(){
    public void actionPerformed(ActionEvent ae){
        try {
            BufferedReader in = new BufferedReader(new FileReader("foo.txt"));
            StringBuffer sb = new StringBuffer();
            char[] buf = new char[4096];
            int n;
            while (-1 != (n = in.read(buf))){
                sb.append(buf, 0, n);
            }
            in.close();
            String s = sb.toString();
            jTextPane1.setText(s);
        } catch (IOException ioe){
            ioe.printStackTrace();
        }

    }
};
jButton1.addActionListener(l);  

All the code inside actionPerformed is executed on the EventQueue thread. No other events could be processed until that code completed. If foo.txt is a big file, then it will be a while before the code completes. This means that every time you click jButton1 before the code finished, it will add the new event to the EventQueue. So if you repeatedly clicked jButton1, then there would be more and more events to add to the queue. You couldn't overflow it this way, because the you couldn't click fast enough, and for long enough without giving up. But if and event such as a mouse move, that occurs at every pixel, leads to a heavy-event. Then that can cause a huge EventQueue queue and it can even cause the EventQueue to overflow. A way to fix this problem might be to start another thread as soon as the event occurs. For example:

final Runnable r = new Runnable() {
    public void run() {
        try {
            BufferedReader in = new BufferedReader(new FileReader("foo.txt"));
            StringBuffer sb = new StringBuffer();
            char[] buf = new char[4096];
            int n;
            while (-1 != (n = in.read(buf))) {
                sb.append(buf, 0, n);
            }
            in.close();
            final String s = sb.toString();
            EventQueue.invokeLater(new Runnable(){
                public void run(){
                    jTextPane1.setText(s);
                }
            });
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
};
ActionListener l = new ActionListener(){
    public void actionPerformed(ActionEvent ae){
        new Thread(r).start();
    }
};
jButton1.addActionListener(l);  

The reason it would be necessary to invoke something on the EventQueue thread, such as in

EventQueue.invokeLater(new Runnable(){
    public void run(){
        jTextPane1.setText(s);
    }
});  

Is because otherwise the screen wouldn't be updated. For example, if maintaining a progress bar, EventQueue.invokeLater() would update the screen NOW, but if it isn't wrapped in EventQueue.invokeLater(), then it will wait until the thread finishes before it updates the screen. That is useless when it comes to progress bars. In this case it probably didn't do much.

Thanx for a great question!

Leo Izen
Thanks for the answer! You are very thorough. My question was regarding Java ME, not Java SE. However, the idea with the `EventQueue` looks like being the same in both. Unfortunately, the answer still doesn't fix my current **J2ME** problem. I'll bear what you said in mind, and will try to fix it myself.
Albus Dumbledore
Well, it was a deadlock, even if NetBeans couldn't find one.
Albus Dumbledore