我有以下问题。我的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的说法是这样),可能会出现什么情况的任何想法都将受到高度赞赏。
谢谢!
最佳答案
当您使用AWT或Swing时,后台运行着一个特殊的线程,称为EventQueue。当您将监听器添加到组件(例如JButton的ActionListener)和事件监听器方法(例如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()
中,则它将等待线程完成,然后再更新屏幕。当涉及进度条时,这是没有用的。在这种情况下,它可能没有做太多事情。谢谢一个很好的问题!