gpt4 book ai didi

java - JTableModelListener.tableChanged() 线程安全吗?

转载 作者:行者123 更新时间:2023-11-29 03:17:43 25 4
gpt4 key购买 nike

tableChanged()JTable 线程的调用是否安全,以便我可以从另一个线程调用它,例如完成下载的东西?我想象 tableChanged() 只是将一个新事件放入事件队列中,以便 Event-Dispatcher-Thread 将在将来的某个时候更新 JTable,但是这样添加线程安全吗?

最佳答案

简短回答不,它不是线程安全的,所有对 tableChanged 的调用都应该在事件调度线程的上下文中进行。

如果您需要更新 TableModel,请将其与表断开连接并在 EDT 范围内通过单个步骤 (setModel) 应用它,或者同步通过使用 SwingWorkerEventQueue.invokeLater

将模型更新回 EDT

Swing 的一般经验法则,假设没有任何东西是线程安全的并对其进行保护。

I imagine tableChanged() to just put a new Event into the Event queue, so that the Event-Dispatcher-Thread will update the JTable at some point in the future, but is this adding thread safe?

并非所有事件都安排在事件队列中,许多事件仅由组件内的 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 方法将在调用它的线程的上下文中执行,并将从同一线程中通知其监听器。

这意味着如果您要从不同的线程调用 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 内,事实上,它根本没有被事件队列调度......

通过 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

关于java - JTableModelListener.tableChanged() 线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25519336/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com