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

标签 java multithreading swing jtable tablemodel

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/

相关文章:

java - 如何禁用 JFrame 中的几乎所有组件?

java - 是否无法动态地将文本添加到单个 JTextArea 中?

java - 如何在android中的数据库上更改数据时得到通知?

java - 通过 netbeans 将 war 部署到 glassfish v3 beta

java - Struts2 jQuery 插件 java.lang.ClassNotFoundException : org. apache.struts2.views.TagLibrary

c++ - 我怎样才能用阻塞写入cout?

sql-server - 跨多个线程处理数据库队列 - 设计建议

java - 为什么我在 JavaFX 上得到 “Not on FX application thread”?

java - JTextArea 作为单元格渲染器似乎不适用于换行样式字

java - 从 Spring Controller 发送重定向