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
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());
}
}
}
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.