Can't get ArrayIndexOutOfBoundsException from Future<?> and SwingWorker if thread starts Executor

后端 未结 2 1166
没有蜡笔的小新
没有蜡笔的小新 2020-11-22 02:07

I play with multitreading for SwingWorker by using Executor, and I\'m there by mistake identified wrong elements from the Vector, looks like as this code pretty ignores that

相关标签:
2条回答
  • 2020-11-22 02:21

    I'm not sure it adds much, but I got the expected Caused by using the variation of takteek's answer shown below. I ran it from the command line to be sure the IDE wasn't "helping".

    $ java -cp build/classes TableWithExecutor
    StartShedule: PENDING -> STARTED
    java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2
        at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
        at java.util.concurrent.FutureTask.get(FutureTask.java:83)
        at javax.swing.SwingWorker.get(SwingWorker.java:582)
        at TableWithExecutor$MyTask.done(TableWithExecutor.java:103)
        at javax.swing.SwingWorker$5.run(SwingWorker.java:717)
        at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:814)
        at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:95)
        at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:824)
        at javax.swing.Timer.fireActionPerformed(Timer.java:291)
        at javax.swing.Timer$DoPostEvent.run(Timer.java:221)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:677)
        at java.awt.EventQueue.access$000(EventQueue.java:85)
        at java.awt.EventQueue$1.run(EventQueue.java:638)
        at java.awt.EventQueue$1.run(EventQueue.java:636)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:647)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
    Caused by: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2
        at java.util.Vector.get(Vector.java:694)
        at TableWithExecutor.changeTableValues(TableWithExecutor.java:64)
        at TableWithExecutor.access$100(TableWithExecutor.java:14)
        at TableWithExecutor$MyTask.doInBackground(TableWithExecutor.java:92)
        at TableWithExecutor$MyTask.doInBackground(TableWithExecutor.java:80)
        at javax.swing.SwingWorker$1.call(SwingWorker.java:277)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at javax.swing.SwingWorker.run(SwingWorker.java:316)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:680)
    StartShedule: STARTED -> DONE
    

    Full code:

    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());
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:38

    I think the problem you're running into is that exceptions caught in the background thread are only re-thrown if you call get() when processing is complete. This seems to be a common problem with SwingWorker.

    You can change your done() function to:

    @Override
    protected void done() {
        if (str.equals("StartShedule")) {
           try {
              get();
           }
           catch (Exception ex) {
              // This exception was thrown during processing
              ex.printStackTrace();
           }
        }
    }
    

    done() gets executed on the event dispatch thread so you can display any error messages you need to from there. I hope that helps some.

    0 讨论(0)
提交回复
热议问题