当您使用AWT或Swing时,会在后台运行一个特殊线程,称为EventQueue。当你将一个监听器添加到一个组件(比如ActionListener到JButton)和事件监听器方法(比如actionPerformed)时,该方法在EventQueue线程上执行。您可以选择到EventQueue线程上执行的东西时,当前线程是无法通过运行
EventQueue.invokeLater(new Runnable(){ //this could also be SwingUtilities.invokeLater() instead
public void run(){
...
}
});
这是伟大的EventQueue上线。当你一遍又一遍地发生一个事件时,问题就来了。发生这种情况时,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为一个伟大的问题!
感谢您的回答!你很彻底。我的问题是关于Java ME,而不是Java SE。然而,使用EventQueue的想法在两者中看起来都是一样的。不幸的是,答案仍然不能解决我目前的** J2ME **问题。我会忍受你所说的话,并会尝试自己解决它。 – 2010-09-12 15:16:18
好吧,这是一个僵局,即使NetBeans找不到一个。 – 2010-09-12 16:18:22