Java:在后台使用大量行更新JTable

Java:在后台使用大量行更新JTable,java,multithreading,swing,jtable,mq,Java,Multithreading,Swing,Jtable,Mq,我正在编写一个简单的JavaSwing实用程序,它将从MQJMS服务器读取消息并在JTable中显示它们 private void getMessages() { try { if (null != Queue) { Queue.close(); //Close previous queue connection if there is one. } Queue = new

我正在编写一个简单的JavaSwing实用程序,它将从MQJMS服务器读取消息并在JTable中显示它们

private void getMessages() {
        try {
            if (null != Queue) {
                Queue.close();  //Close previous queue connection if there is one.
            }
            Queue = new MQQueue(QueueManager, tableQueues.getValueAt(tableQueues.getSelectedRow(), 1).toString(), MQConstants.MQOO_INPUT_SHARED | MQConstants.MQOO_BROWSE | MQConstants.MQOO_OUTPUT, queueManager, null, null);
            int count = 0;
            modelMessages.setRowCount(0);
            MQGetMessageOptions getOptions = new MQGetMessageOptions();
            getOptions.options = MQConstants.MQGMO_BROWSE_FIRST;
            ArrayList<Object[]> rows = new ArrayList<Object[]>();
            while(true) {
                if (count > 0) {
                    getOptions.options = MQConstants.MQGMO_BROWSE_NEXT;
                }
                MQMessage message = new MQMessage();
                try {
                    Queue.get(message, getOptions);
                    byte[] b = new byte[message.getMessageLength()];
                    message.readFully(b);
                    rows.add(new Object[]{count + 1, new String(b)});
                    modelMessages.addRow(new Object[]{count + 1, new String(b)});
                    message.clearMessage();
                    count++;
                }
                catch (IOException e) {
                    break;
                }
                catch (MQException e) {
                    if (e.completionCode == 2 && e.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) {
                        break;
                    }
                }
            }
            modelMessages.fireTableDataChanged();
        } catch (MQException e) {
            txtMessage.setText("MQJE001: Completion Code '" + e.completionCode + "', Reason '" + e.reasonCode + "'.");
            modelMessages.setRowCount(0);
            modelMessages.fireTableDataChanged();
        }
    }

在Swing中执行线程时,您需要了解您必须在后台线程中执行工作,但是任何UI更新都必须在Swing线程中完成

这意味着您应该创建一个线程来获取消息。如果有一个(或多个),则使用
SwingUtilities
与Swing线程同步并更新表

在上面的代码片段中,这意味着每次调用
modelMessages
txtMessage
等方法时都需要使用
SwingUtilities


由于这相当昂贵,您通常会收集(比如)列表中的10个新行,然后使用对
SwingUtilities.invokeLater()
的单个调用一次将它们全部添加到列表中,这是由于Swing体系结构的缘故。您必须理解,执行侦听器的线程负责更多的事情(例如,刷新UI)

在你的情况下,我会使用
SwingWorker
。这是一种特定于Swing的后台线程,具有特殊功能,可以在UI执行其长任务时安全地向UI发送更新。您可以在后台执行长任务,并调用
publish()
获取每个相关结果。每次调用
publish()
时,都会调用您的
process()
方法(向引擎盖下的主线程发送更新),您可以在那里更新表模型

在这里,您可以找到有关SwingWorker的更多信息:


+1用于SwingWorker,并链接到Swing教程。SwingWorker似乎在为我工作,我几乎可以工作了(完成后将用解决方案更新问题)。一个问题—我的应用程序有两个表—左侧是JMS队列列表,右侧是突出显示队列中的消息列表。选择新队列时,消息将显示在右表中。我在ActionListener中有“new GetMessagesWorker(modelMessages).execute();”,但如果我在队列仍在填充时更改队列,它不会干净地结束,并在焦点更改后继续一段时间。我该如何解决这个问题?也许您可以保留打开的
SwingWorkers
的记录,并在其上定义一些同步状态属性。在轮询JMS队列之前,在主循环中检查它,并在希望它停止时从外部将其更新为“停止”。。。我不知道这是否是你最好的选择,但我认为这样做会奏效的。SwingWorker和MQ有三个重要的问题,SwingWorker没有被指定为可重用的,因为MQ中的periodical getXxx()最好使用util.Timer和invokeLater来更新Swing GUI或JComponents XxxModel,异常(默认整个体系结构)MQ是非常异步的, ,
public class GetMessagesWorker extends SwingWorker<DefaultTableModel, Object[]> {

    //http://stackoverflow.com/questions/22072480/java-updating-jtable-with-lots-of-rows-in-the-background#

    private final DefaultTableModel model;

    public GetMessagesWorker(DefaultTableModel model){
        this.model = model;
    }

    @Override
    protected DefaultTableModel doInBackground() throws Exception {
        try {
            if (null != Queue) {
                Queue.close();  //Close previous queue connection if there is one.
            }
            Queue = new MQQueue(QueueManager, tableQueues.getValueAt(tableQueues.getSelectedRow(), 1).toString(), MQConstants.MQOO_INPUT_SHARED | MQConstants.MQOO_BROWSE | MQConstants.MQOO_OUTPUT, queueManager, null, null);
            int count = 0;
            modelMessages.setRowCount(0);
            MQGetMessageOptions getOptions = new MQGetMessageOptions();
            getOptions.options = MQConstants.MQGMO_BROWSE_FIRST;
            while(true) {
                if (count > 0) {
                    getOptions.options = MQConstants.MQGMO_BROWSE_NEXT;
                }
                MQMessage message = new MQMessage();
                try {
                    Queue.get(message, getOptions);
                    byte[] b = new byte[message.getMessageLength()];
                    message.readFully(b);
                    Object[] row = {count + 1, new String(b)};
                    publish(row);
                    message.clearMessage();
                    count++;
                    if (isCancelled()) {
                        modelMessages.setRowCount(0);
                        count = 0;
                        message.clearMessage();
                        return model;
                    }
                }
                catch (IOException e) {
                    break;
                }
                catch (MQException e) {
                    if (e.completionCode == 2 && e.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) {
                        break;
                    }
                }
            }
            //modelMessages.fireTableDataChanged();
        } catch (MQException e) {
            txtMessage.setText("MQJE001: Completion Code '" + e.completionCode + "', Reason '" + e.reasonCode + "'.");
            modelMessages.setRowCount(0);
            modelMessages.fireTableDataChanged();
        }
        return model;
    }

    @Override
    protected void process(List<Object[]> chunks){
        for(Object[] row : chunks){
            model.addRow(row);
        }
    }

}
    tableQueues = new JTable(modelQueues);
    tableQueues.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
        public void valueChanged(ListSelectionEvent e) {
            if (!e.getValueIsAdjusting()) {
                txtMessage.setText("");
                if (tableQueues.getSelectedRow() > -1) {
                    gmw.cancel(false);
                    gmw = new GetMessagesWorker(modelMessages);
                    gmw.execute();
                }
            }
        }
    });