如果线程启动Executor,则无法从Future <?>和SwingWorker获取ArrayIndexOutOfBoundsException
我使用Executor来玩SwingWorker的multithreading,而且我从那里错误的发现了Vector中的错误元素,看起来像这段代码很可能忽略了Vector中不存在的元素
我的问题 – >如何/有可能以某种方式捕捉这个exception
简单的输出
run: Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE BUILD SUCCESSFUL (total time: 11 seconds)
通过取消注释
//changeTableValues1(); // un-comment for get ArrayIndexOutOfBoundsException
一切正常,我得到ArrayIndexOutOfBoundsException和输出是
run: Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2 at java.util.Vector.get(Vector.java:694) at KondorExport.Util.Help.Table.TableWithExecutor.changeTableValues1(TableWithExecutor.java:70) at KondorExport.Util.Help.Table.TableWithExecutor.access$100(TableWithExecutor.java:18) at KondorExport.Util.Help.Table.TableWithExecutor$2.actionPerformed(TableWithExecutor.java:61) at javax.swing.Timer.fireActionPerformed(Timer.java:271) at javax.swing.Timer$DoPostEvent.run(Timer.java:201) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE BUILD SUCCESSFUL (total time: 10 seconds)
来自代码
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import java.util.Vector; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.swing.*; import javax.swing.table.*; public class TableWithExecutor extends JFrame { private static final long serialVersionUID = 1L; private String[] columnNames = {"Narrative", "Description"}; private Object[][] data = {{"About", "About"}, {"Add", "Add"}}; private JTable table; private Executor executor = Executors.newCachedThreadPool(); private Timer timerRun; private int delay = 3000; private Vector<String> fwDeals; private Vector<String> fwDeals1; public TableWithExecutor() { DefaultTableModel model = new DefaultTableModel(data, columnNames); table = new JTable(model) { private static final long serialVersionUID = 1L; @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; table.setPreferredScrollableViewportSize(table.getPreferredSize()); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane, BorderLayout.CENTER); prepareStartShedule(); } private void prepareStartShedule() { timerRun = new javax.swing.Timer(delay, startCycle()); timerRun.setRepeats(true); timerRun.start(); } private Action startCycle() { return new AbstractAction("Start Shedule") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { executor.execute(new TableWithExecutor.MyTask("StartShedule")); //non on EDT //changeTableValues1(); // un-comment for get ArrayIndexOutOfBoundsException } }; } private void changeTableValues1() { fwDeals1 = new Vector<String>(); fwDeals1.add("First"); // ElementAt(0) fwDeals1.add("Second");// ElementAt(1) checkDealsInDb1(fwDeals1.get(1), fwDeals1.get(2)); } private void checkDealsInDb1(String Str, String Str1) { table.getModel().setValueAt(Str, 0, 1); table.getModel().setValueAt(Str1, 1, 1); } private void changeTableValues() { fwDeals = new Vector<String>(); fwDeals.add("First"); // ElementAt(0) fwDeals.add("Second");// ElementAt(1) checkDealsInDb(fwDeals.get(1), fwDeals.get(2)); } private void checkDealsInDb(String Str, String Str1) { table.getModel().setValueAt(Str, 0, 1); table.getModel().setValueAt(Str1, 1, 1); } public static void main(String[] args) { TableWithExecutor frame = new TableWithExecutor(); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.setLocation(150, 150); frame.pack(); frame.setVisible(true); } private class MyTask extends SwingWorker<Void, Integer> { private String str; private String namePr; MyTask(String str) { this.str = str; addPropertyChangeListener(new SwingWorkerCompletionWaiter(str, namePr)); } @Override protected Void doInBackground() throws Exception { if (str.equals("StartShedule")) { changeTableValues(); } return null; } @Override protected void process(List<Integer> progress) { } @Override protected void done() { if (str.equals("StartShedule")) { } } } private class SwingWorkerCompletionWaiter implements PropertyChangeListener { private String str; private String namePr; SwingWorkerCompletionWaiter(String str, String namePr) { this.str = str; this.namePr = namePr; } SwingWorkerCompletionWaiter(String namePr) { this.namePr = namePr; } @Override public void propertyChange(PropertyChangeEvent event) { if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) { System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else { System.out.println("SomeThing Wrong happends with Thread Status with Name :" + str); } } } }
编辑:
添加从未来#重新抛出()done()方法(由@takteek优秀的build议)
@Override protected void done() { if (str.equals("StartShedule")) { try { get(); //errLabel.setText(String.valueOf(get())); } catch (InterruptedException ie) { ie.printStackTrace(); } catch (ExecutionException ee) { ee.printStackTrace(); }catch (IllegalStateException is) { is.printStackTrace(); } } }
但输出仍然是唯一的Got exception
,将很难从这BlackBox的任何例外
run: Got exception Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE Got exception Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE Got exception Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE Got exception Thread Status with Name :StartShedule, SwingWorker Status is STARTED Thread Status with Name :StartShedule, SwingWorker Status is DONE BUILD SUCCESSFUL (total time: 13 seconds)
我不确定它增加了多less,但我得到了预期Caused by
使用下面显示的takteek的答案的变化Caused by
。 我从命令行运行它,以确保IDE不“帮助”。
$ java -cp build / classes TableWithExecutor StartShedule:PENDING - > STARTED java.util.concurrent.ExecutionException:java.lang.ArrayIndexOutOfBoundsException:数组索引超出范围:2 在java.util.concurrent.FutureTask $ Sync.innerGet(FutureTask.java:222) 在java.util.concurrent.FutureTask.get(FutureTask.java:83) 在javax.swing.SwingWorker.get(SwingWorker.java:582) 在TableWithExecutor $ MyTask.done(TableWithExecutor.java:103) 在javax.swing.SwingWorker $ 5.run(SwingWorker.java:717) 在javax.swing.SwingWorker $ DoSubmitAccumulativeRunnable.run(SwingWorker.java:814) 在sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:95) 在javax.swing.SwingWorker $ DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:824) 在javax.swing.Timer.fireActionPerformed(Timer.java:291) 在javax.swing.Timer $ DoPostEvent.run(Timer.java:221) 在java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) 在java.awt.EventQueue.dispatchEventImpl(EventQueue.java:677) 在java.awt.EventQueue.access $ 000(EventQueue.java:85) 在java.awt.EventQueue $ 1.run(EventQueue.java:638) 在java.awt.EventQueue $ 1.run(EventQueue.java:636) 在java.security.AccessController.doPrivileged(本地方法) 在java.security.AccessControlContext $ 1.doIntersectionPrivilege(AccessControlContext.java:87) 在java.awt.EventQueue.dispatchEvent(EventQueue.java:647) 在java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296) 在java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211) 在java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201) 在java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196) 在java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188) 在java.awt.EventDispatchThread.run(EventDispatchThread.java:122) 引起:java.lang.ArrayIndexOutOfBoundsException:数组索引超出范围:2 在java.util.Vector.get(Vector.java:694) 在TableWithExecutor.changeTableValues(TableWithExecutor.java:64) 在TableWithExecutor.access $ 100(TableWithExecutor.java:14) 在TableWithExecutor $ MyTask.doInBackground(TableWithExecutor.java:92) 在TableWithExecutor $ MyTask.doInBackground(TableWithExecutor.java:80) 在javax.swing.SwingWorker $ 1.call(SwingWorker.java:277) 在java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:303) 在java.util.concurrent.FutureTask.run(FutureTask.java:138) 在javax.swing.SwingWorker.run(SwingWorker.java:316) 在java.util.concurrent.ThreadPoolExecutor $ Worker.runTask(ThreadPoolExecutor.java:886) 在java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:908) 在java.lang.Thread.run(Thread.java:680) StartShedule:已开始 - >完成
完整代码:
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.DateFormat; import java.util.Date; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.swing.*; import javax.swing.table.*; /** @see https://stackoverflow.com/questions/7054627 */ public class TableWithExecutor extends JFrame { private static final int delay = 1000; private static final DateFormat df = DateFormat.getTimeInstance(); private String[] columnNames = {"Product", "Availability"}; private Object[][] data = {columnNames, columnNames, columnNames}; private DefaultTableModel model; private JTable table; private Executor executor = Executors.newCachedThreadPool(); private Timer timer; public TableWithExecutor() { model = new DefaultTableModel(data, columnNames); table = new JTable(model) { @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; table.setDefaultRenderer(Date.class, new DefaultTableCellRenderer() { @Override protected void setValue(Object value) { setText((value == null) ? "" : df.format(value)); } }); table.setPreferredScrollableViewportSize(new Dimension(200, 100)); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane, BorderLayout.CENTER); timer = new Timer(delay, startCycle()); timer.setRepeats(true); timer.start(); } private Action startCycle() { return new AbstractAction(MyTask.STARTSCHEDULE) { @Override public void actionPerformed(ActionEvent e) { executor.execute(new MyTask(MyTask.STARTSCHEDULE)); } }; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { TableWithExecutor frame = new TableWithExecutor(); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } private class MyTask extends SwingWorker<List<DateRecord>, DateRecord> { private static final String STARTSCHEDULE = "StartSchedule"; private String name = STARTSCHEDULE; MyTask(String name) { this.name = name; addPropertyChangeListener(new TaskListener(name)); } @Override protected List<DateRecord> doInBackground() throws Exception { for (int row = 0; row < model.getRowCount(); row++) { Date date = new Date(); date.setTime(date.getTime() + row * 1000); publish(new DateRecord(row, date)); } return null; } @Override protected void process(List<DateRecord> chunks) { for (DateRecord dr : chunks) { model.setValueAt(dr.date, dr.rowNumber, 1); } } @Override protected void done() { try { get(); } catch (Exception e) { e.printStackTrace(System.err); } } } private static class DateRecord { private int rowNumber; private Date date; public DateRecord(int recordNumber, Date date) { this.rowNumber = recordNumber; this.date = date; } } private static class TaskListener implements PropertyChangeListener { private String name; TaskListener(String name) { this.name = name; } @Override public void propertyChange(PropertyChangeEvent e) { System.out.println(name + ": " + e.getOldValue() + " -> " + e.getNewValue()); } } }
我认为你遇到的问题是在后台线程中捕获的exception只有在处理完成时调用get()
才会重新抛出。 这似乎是SwingWorker的常见问题。
您可以将您的done()
函数更改为:
@Override protected void done() { if (str.equals("StartShedule")) { try { get(); } catch (Exception ex) { // This exception was thrown during processing ex.printStackTrace(); } } }
done()
在事件派发线程上执行,所以你可以从那里显示你需要的任何错误信息。 我希望有一些帮助。