Когда вы используете 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 для отличного вопроса!
Спасибо за ответ! Вы очень основательны. Мой вопрос касался Java ME, а не Java SE. Однако идея с «EventQueue» выглядит как одна и та же. К сожалению, ответ по-прежнему не устраняет мою текущую проблему ** J2ME **. Я возьму то, что вы сказали, и попытается исправить это сам. –
Ну, это был тупик, даже если NetBeans не смог его найти. –