高頻率新增/刪除 JTable 資料時,若直接在事件派發執行緒(EDT)外操作 DefaultTableModel,極易發生 ArrayIndexOutOfBoundsException。解決之道:所有模型變更務必封裝在 SwingUtilities.invokeLater 執行,確保單一執行緒存取模型。
// 直接操作模型 → 會拋出 ArrayIndexOutOfBoundsException
public void addValueWithoutThread(Vector value) {
model.addRow(value);
if (model.getRowCount() > 5) deleteRows(2);
}
// 包裝在 invokeLater → 穩定不報錯
public void addValueWithThread(final Vector value) {
new Thread(() -> {
SwingUtilities.invokeLater(() -> {
model.addRow(value);
if (model.getRowCount() > 5) deleteRows(2);
});
}).start();
}
public class ThreadTable extends JTable {
private DefaultTableModel model;
static String[] header = {"id","name","sex","age"};
public ThreadTable() {
model = new DefaultTableModel(header, 0);
setModel(model);
}
public void deleteRows(int rowCount) throws Exception {
if (rowCount >= model.getRowCount()) throw new Exception("刪除行數超過總行數");
for (int i = rowCount - 1; i >= 0; i--) model.removeRow(i);
}
public void testInsertValue() {
Vector value = new Vector<>(Arrays.asList("0","simon","boy","21"));
new Thread(() -> {
for (int i = 0; i < 100000; i++) {
addValueWithThread(value); // 或 addValueWithoutThread 對比
try { Thread.sleep(10); } catch (InterruptedException ignored) {}
}
}).start();
}
// addValueWithThread / addValueWithoutThread 如上
public static void main(String[] args) { /* 建立 JFrame 顯示 */ }
}
TableModel、ListModel、TreeModel 等)非執行緒安全,所有讀寫必須在 EDT 執行。SwingUtilities.invokeLater(Runnable) 排程模型更新。invokeLater 中完成多筆增刪,減少重繪開銷。遵循此模式,JTable 即使在極高頻率資料流下亦能穩定運作。