Java中的线程问题

时间:2010-09-12 13:59:16

标签: java multithreading java-me deadlock

我有以下问题。我的J2ME应用程序完全死了。我虽然陷入僵局,但是使用NetBeans的内置功能,却无法找到它。

但是经过一段时间后,它开始在控制台中抛出以下消息:

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

等等。

如果死锁(在NetBeans所说的那些内容)可能是什么情况下的任何想法都将受到高度赞赏。

谢谢!

1 个答案:

答案 0 :(得分:2)

当您使用AWT或Swing时,后台会运行一个特殊的线程,称为EventQueue。将侦听器添加到组件(例如ActionListener到JButton)和事件侦听器方法(例如actionPerformed)时,将在EventQueue线程上执行该方法。当前线程不是EventQueue线程时,您可以通过运行

选择在EventQueue线程上执行某些操作
EventQueue.invokeLater(new Runnable(){ //this could also be SwingUtilities.invokeLater() instead
    public void run(){
        ...
    }
});

这很棒。当你有一个一遍又一遍的事件时,就会出现问题。发生这种情况时,EventQueue线程无法足够快地执行上一个事件的代码以执行下一个事件的代码。因此它在等待当前事件处理程序完成时将事件粘贴到队列中。当您在EventQueue线程上执行大型操作(例如从文件读取)时,可能会发生这种情况。例如:

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);  

actionPerformed内的所有代码都在EventQueue线程上执行。在该代码完成之前,不能处理任何其他事件。如果foo.txt是一个大文件,那么代码完成之前会有一段时间。这意味着每次在代码完成之前单击jButton1,它都会将新事件添加到EventQueue。因此,如果您反复单击jButton1,则会有越来越多的事件要添加到队列中。你不能以这种方式溢出它,因为你不能足够快地点击,并且足够长时间而不放弃。但是,如果鼠标移动等事件发生在每个像素上,则会导致重大事件。然后,这可能会导致巨大的EventQueue队列,甚至可能导致EventQueue溢出。解决此问题的方法可能是在事件发生后立即启动另一个线程。例如:

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);  

需要在EventQueue线程上调用某些内容的原因,例如在

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

是因为否则屏幕不会更新。例如,如果维护进度条,EventQueue.invokeLater()将立即更新屏幕,但如果它未包含在EventQueue.invokeLater()中,则它将等到线程完成后再更新屏幕。当涉及到进度条时,这是没用的。在这种情况下,它可能没有做太多。

Thanx提出了一个很棒的问题!