是tableChanged()
在通话JTable
线程安全的,所以允许我从另一个线程,例如下载完的东西称呼呢? 我想象tableChanged()
只是把一个新的事件加入到事件队列中,让事件调度线程将更新JTable
在未来的某个时刻,但这种增加线程安全的?
Answer 1:
简短的回答没有,它不是线程安全,将所有来电tableChanged
应该从事件指派线程的上下文中进行。
如果您需要更新TableModel
,无论是从表中断开,并在一个单一的步骤(应用它setModel
将EDT的范围内),或者通过使用的同步更新到模型回EDT SwingWorker
或EventQueue.invokeLater
一般的经验法则与Swing,假设没有什么是线程安全和保护功能。
我想象tableChanged()只是把一个新的事件加入到事件队列中,让事件调度线程将在未来的某个时刻更新的JTable,但这种增加线程安全的?
并非所有的事件被安排在事件队列中,许多人都简单地通过处理for-next
组件内循环,直接通过注册的侦听器循环,如对于情况TableModel
的fire
事件方法...
例如,从AbstractTableModel
...
public void fireTableChanged(TableModelEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==TableModelListener.class) {
((TableModelListener)listeners[i+1]).tableChanged(e);
}
}
}
这意味着fireTableChanged
方法调用它的线程的上下文中执行,并将来自相同线程内notifiy其侦听器。
这意味着,如果你要调用TableModel.setValueAt
从不同的线程,它会调用fireTableCellUpdated
,这将调用fireTableChanged
并最终调用tableChanged
该线程的上下文中...
作为一个侧面说明,你不应该调用JTable#tableChanged
直接,这是公众的副作用(当内部类是绕不JTable
创建;)),你应该进行修改表的模型,并允许模型触发事件的通知。
更新...
考虑这个非常基本的测试...
public class Test {
public static void main(String[] args) {
DefaultTableModel model = new DefaultTableModel(new String[]{"One"}, 1);
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
System.out.println("isEventDispatchingThread - " + EventQueue.isDispatchThread());
}
});
model.setValueAt("Test", 0, 0);
}
}
将输出...
isEventDispatchingThread - false
因为更新未在美国东部时间内发生,事实上,它不是事件队列中的所有派遣...
更新了EDT的实例和单独的更新线程
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Boo"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
DefaultTableModel model = new DefaultTableModel(new String[]{"One"}, 1);
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
System.out.println("isEventDispatchingThread - " + EventQueue.isDispatchThread());
}
});
Thread t = new Thread(new Runnable() {
@Override
public void run() {
model.setValueAt("Test", 0, 0);
}
});
t.start();
}
});
}
}
输出...
isEventDispatchingThread - false
文章来源: JTableModelListener.tableChanged() thread safe?