简体   繁体   English

如何根据从其他线程中长时间运行的任务收到的​​通知更新JTable?

[英]How do I update a JTable based on a notification received from a long-running task in other thread?

I've an Observer TableModel which listens to some changes, performed in the database, and when so the update method below is called. 我有一个Observer TableModel,它监听在数据库中执行的一些更改,然后调用下面的更新方法。 My problem is, how should I prevent errors like: 我的问题是,我应该如何防止错误:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.set(ArrayList.java:337)
at com.mysimpatico.memoplatform.persistenceui.MeaningsViewerTopComponent$DefaultTableModelImpl.update(MeaningsViewerTopComponent.java:108)

I don't see how SwingWorker would help. 我不知道SwingWorker会如何提供帮助。 I've the long-running database task being performed in a separate thread, but this calls upon a method (database persisting) in an Observable class which notifies observers. 我在一个单独的线程中执行长时间运行的数据库任务,但是这会在Observable类中调用一个方法(数据库持久化)来通知观察者。

@Override
        public void update(Observable o, final Object arg) {
            final Meaning meng = (Meaning) arg;
            final int row;
            final boolean insert;
            synchronized (mengs) {
                if (mengs.contains(meng)) {
                    row = meng.getObjId();
                    mengs.set(row, meng);
                    insert = false;
                } else {
                    row = mengs.size();
                    mengs.add(row, meng); //last
                    insert = true;
                }
                try {
                    SwingUtilities.invokeAndWait(new Runnable() {

                    @Override
                    public void run() {
                        if (insert) {
                            fireTableRowsInserted(row, row);
                        } else {
                            fireTableRowsUpdated(row, row);
                        }
                    }
                });
            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            } catch (InvocationTargetException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }

Despite firing insert / update TableModelEvent s on the event dispatch thread you're actually updating the TableModel on whichever thread is performing the notification of the database update. 尽管在事件调度线程上触发插入/更新TableModelEvent ,但实际上在执行数据库更新通知的任何线程上都会更新TableModel This is dangerous as it means: 这很危险,因为它意味着:

  • The event dispatch thread could potential see the TableModel in an inconsistent state. 事件调度线程可能会看到TableModel处于不一致状态。
  • The event dispatch thread could be attempting to render the TableModel as the notification thread is altering it. 事件调度线程可能正在尝试呈现TableModel因为通知线程正在改变它。

The solution should (in theory) simply be a case of moving your call to SwingUtilities.invokeAndWait to outside the block of code that begins: synchronized(mengs) . 解决方案应该(理论上)只是将您对SwingUtilities.invokeAndWait的调用移到开始的代码块之外: synchronized(mengs) Also, once you've done this you can actually removed the synchronized keyword entirely as all access to your model will be done on the EDT. 此外,一旦完成此操作,您实际上可以完全删除synchronized关键字,因为对模型的所有访问都将在EDT上完成。

As an aside I would avoid using the Observer / Observable classes (for more information see my answer to this question ); Observable我会避免使用Observer / Observable类(有关更多信息,请参阅我对此问题的回答 ); far better to define domain-specific listener interfaces and event classes (that subclass java.util.EventObject ). 更好地定义特定于域的侦听器接口和事件类(子类java.util.EventObject )。

Are your indexes correct? 你的索引是否正确?

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 

The above statement says you only have one entry in the array list. 上面的语句说你只在数组列表中有一个条目。 I can't tell if your code is an "add" or an "update". 我不知道你的代码是“添加”还是“更新”。 But remember that ResultSet indexes are 1 based not 0 based so maybe you need to subtract 1 from all your row values? 但请记住,ResultSet索引是基于1而不是基于0,所以可能需要从所有行值中减去1?

One option is using a org.jdesktop.application.Task . 一种选择是使用org.jdesktop.application.Task You will need to pass the TableModel to the Task and then so a simple TableModel.insert call. 您需要将TableModel传递给Task,然后再进行简单的TableModel.insert调用。

Note: The task is just a nice wrapper around a Thread. 注意:任务只是围绕Thread的一个很好的包装器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从另一个servlet中杀死一个长时间运行的servlet进程? - How do I kill a long-running servlet process from another servlet? 如何使用Apache Camel处理长时间运行的任务 - How to handle Long-Running Task with Apache Camel 如何使用从另一个线程收到的信息更新主UI? (虽然线程仍在运行) - How can I update the Main UI with information received from another thread? (While the thread is still running) 如何从 EDT 将 object 交付给长期运行的 SwingWorker? - How to deliver object to a long-running SwingWorker from the EDT? 我是否可以滥用浏览器超时以避免由于长时间运行的任务而忙于轮询服务器 - Can I abuse the browser timeout to avoid busy-polling the server for the result of a long-running task 使用现有的EJB服务从Tapestry执行长期运行的任务 - Executing long-running task from Tapestry using already existing EJB service 如何更新JTable? - How do I update a JTable? 与可能长时间运行的后台任务结合使用的摆动计时器 - Swing Timer in Conjunction with Possible Long-running Background Task 如何处理长时间运行不稳定的服务器 - How to handle long-running unstable server 如何执行长时间运行的任务? - How to execute long-running tasks?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM