JTableModelListener.tableChanged()是线程安全的?(JTableMo

2019-10-20 19:39发布

tableChanged()在通话JTable线程安全的,所以允许我从另一个线程,例如下载完的东西称呼呢? 我想象tableChanged()只是把一个新的事件加入到事件队列中,让事件调度线程将更新JTable在未来的某个时刻,但这种增加线程安全的?

Answer 1:

简短的回答没有,它不是线程安全,将所有来电tableChanged应该从事件指派线程的上下文中进行。

如果您需要更新TableModel ,无论是从表中断开,并在一个单一的步骤(应用它setModel将EDT的范围内),或者通过使用的同步更新到模型回EDT SwingWorkerEventQueue.invokeLater

一般的经验法则与Swing,假设没有什么是线程安全和保护功能。

我想象tableChanged()只是把一个新的事件加入到事件队列中,让事件调度线程将在未来的某个时刻更新的JTable,但这种增加线程安全的?

并非所有的事件被安排在事件队列中,许多人都简单地通过处理for-next组件内循环,直接通过注册的侦听器循环,如对于情况TableModelfire事件方法...

例如,从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?