我试图将项目异步添加到JList,但我经常从另一个线程获取异常,例如:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 8有谁知道如何解决这一问题?
(编辑:我回答了这个问题,因为它一直在窃听我,并没有明确的搜索引擎友好的方式来查找此信息。)
I'm trying to add items to a JList asynchronously but I am regularly getting exceptions from another thread, such as:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 8Does anyone know how to fix this?
(EDIT: I answered this question because it's been bugging me and there is no clear search engine friendly way of finding this info.)
最满意答案
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); } } });Swing components are NOT thread-safe and may sometimes throw exceptions. JList in particular will throw ArrayIndexOutOfBounds exceptions when clearing and adding elements.
The work-around for this, and the preferred way to run things asynchronously in Swing, is to use the invokeLater method. It ensures that the asynchronous call is done when all other requests.
Example using SwingWorker (which implements 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);Of course you don't need to use a SwingWorker as you can just implement a Runnable instead like this:
// 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); } } });更多推荐
发布评论