Компоненты Swing НЕ поточнобезопасны и могут иногда выдавать исключения. JList, в частности, будет выдавать ArrayIndexOutOfBounds исключений при очистке и добавлении элементов.
Обходной путь для этого и предпочтительный способ асинхронного запуска вещей в Swing - это использование invokeLater
метода . Это обеспечивает выполнение асинхронного вызова при выполнении всех других запросов.
Пример использования SwingWorker
(который реализует Runnable
):
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void> () {
@Override
protected Void doInBackground() throws Exception {
Collection<Object> objects = doSomethingIntense();
this.myJList.clear();
for(Object o : objects) {
this.myJList.addElement(o);
}
return null;
}
}
// This WILL THROW EXCEPTIONS because a new thread will start and meddle
// with your JList when Swing is still drawing the component
//
// ExecutorService executor = Executors.newSingleThreadExecutor();
// executor.execute(worker);
// The SwingWorker will be executed when Swing is done doing its stuff.
java.awt.EventQueue.invokeLater(worker);
Конечно, вам не нужно использовать SwingWorker
, поскольку вы можете просто реализовать Runnable
вместо этого следующим образом:
// This is actually a cool one-liner:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Collection<Object> objects = doSomethingIntense();
this.myJList.clear();
for(Object o : objects) {
this.myJList.addElement(o);
}
}
});