java - 为什么 doAction() 提前完成了 done() ?

标签 java swing concurrency swingworker

我有一个奇怪的问题。我有一个带有 for 循环的 doAction() Swingworker,用于从 JTable 和数据库中删除行。如果 for 循环很大,则 done() 方法将在循环完成之前触发,从而有效地中途停止执行。

我的代码:

 public void doAction() throws Exception {
    int selectedRows[];
    int modelRows[];
    java.util.ArrayList<customRecord> condemned;
    customTableModel dataSource;
    boolean databaseDelete = false;
    Object uniqueID;
    int rowCount = 0;

    dataSource = (customTableModel)table.getModel();
    selectedRows = table.getSelectedRows();

    condemned = new java.util.ArrayList<customRecord>();
    modelRows = new int[selectedRows.length];

    for(int i=0;i<selectedRows.length;i++)
        modelRows[i] = table.convertRowIndexToModel(selectedRows[i]);

    selectedRows = null;

    for(int i= 0; i < modelRows.length; i++){
        uniqueID = dataSource.getUniqueID(modelRows[i]);

        System.out.println("Debug: spot 1, rowCount = " + rowCount + ", i = " + i + ", length = " + modelRows.length);

        if(uniqueID == null)
            dataSource.removeRow(modelRows[i]);
        else if(adminPrivileges){
            condemned.add(//Record being looked at);
            databaseDelete = true;

            System.out.println("Debug: spot 2, rowCount = " + rowCount + ", i = " + i);

            dataSource.removeRow(modelRows[i]);
            if(condemned.size() >= 100){
                database.clearData(condemned);
                condemned.clear();
            }

            System.out.println("Debug: spot 3, rowCount = " + rowCount + ", i = " + i);

        }

        System.out.println("Debug: spot 4, rowCount = " + rowCount + ", i = " + i + ", uniqueID = " + uniqueID.toString() + "\n");

        if(++rowCount >= 1000){
            System.out.println("rowCount = " + rowCount + ", in break");
            break;
        }
    }

    if(databaseDelete){
        if(condemned.size() > 0)
            database.clearData(condemned);
        loadData(table,database,filterParams);
    }
}

public void done() {

    System.out.println("Debug: in done()");

    table.setVisible(true);
    //Display warning message if the number of rows reached the limit
    if(rowCount >= 1000){
        // Display Limit Reached Warning;
    }
}

我的输出如下所示:

Debug: spot 1, rowCount = 0, i = 0, length 1006
Debug: spot 2, rowCount = 0, i = 0
Debug: spot 3, rowCount = 0, i = 0
Debug: spot 4, rowCount = 0, i = 0, uniqueID = 2608
.
.
.
Debug: spot 1, rowCount = 505, i = 505, length = 1006
Debug: spot 2, rowCount = 505, i = 505
Debug: spot 3, rowCount = 505, i = 505
Debug: spot 4, rowCount = 505, i = 505, uniqueID = 3073

Debug: spot 1, rowCount = 506, i = 506, length = 1006
Debug: in done()

如果大for循环设置为从大到小,如for(i = modelRows.length-1; i >= 0; i--)它会更进一步:

Debug: spot 1, rowCount = 0, i = 1005, length 1006
Debug: spot 2, rowCount = 0, i = 1005
Debug: spot 3, rowCount = 0, i = 1005
Debug: spot 4, rowCount = 0, i = 1005, uniqueID = 3073
.
.
.
Debug: spot 1, rowCount = 899, i = 106, length = 1006
Debug: spot 2, rowCount = 899, i = 106
Debug: spot 3, rowCount = 899, i = 106
Debug: spot 4, rowCount = 899, i = 106, uniqueID = 2174

Debug: in done()

如何使/允许此 doAction() 方法正确完成?在调用 done() 方法之前 Swingworker 执行的最长时间是否存在?

编辑

我相信我自己(可能还有其他人)都困惑于说 doAction() 是一个 SwingWorkerdoAction() 是从扩展 SwingWorker 的类中的 doInBackground() 调用的方法。

代码:

protected interface LengthyAction{

    public customActions getAction();

    public java.awt.Component getComponent();

    public void doAction() throws Exception;

    public void done();

}

private class DataSwingWorker extends javax.swing.SwingWorker{

    private LengthyAction action;

    public DataSwingWorker(LengthyAction targetAction){
        action = targetAction;
        setCursor(action.getComponent(),java.awt.Cursor.WAIT_CURSOR);
        if(listener != null)
            listener.actionPerformed(new java.awt.event.ActionEvent(**stuff**));
    }
    .
    .
    .
    @Override
    protected Object doInBackground() throws Exception {
        action.doAction();
        return null;            
    }

    @Override
    protected void done() {
        if(listener != null)
            listener.actionPerformed(new java.awt.event.ActionEvent(**stuff**));                
        action.done();
    }

}

我找到了问题的答案,而且它确实与我最初的想法无关。取出:

if(condemned.size() >= 100){
    database.clearData(condemned);
    condemned.clear();
}

在大的 doAction() for 循环中,一切都正常。这似乎导致 uniqueID 向前跳 100 个位置,并且我在循环结束之前到达了数组的末尾,给出了 NullPointerException

感谢您的所有帮助,它最终使我走上了正确的道路。

最佳答案

我将尝试根据您发布的数据回答目前看来可以回答的问题:

I have a doAction() Swingworker with a for loop to remove rows from a JTable and a data base ...... No, it is a doAction() method on an object that is called from a doInBackground() method.

这不太好。如果您从 SwingWorker 的 doInBackground() 方法中调用 doAction(),则意味着您的代码通过进行 Swing 调用(尤其是会改变Swing 组件的状态,来自后台线程。事实上,这可能是导致该后台线程运行时出现间歇性问题的原因,或者至少是一个主要因素。

Is there a maximum time a Swingworker will execute before the done() method is called?

没有。当 doInBackground() 方法完成其操作并且未发现异常时调用它。一个关键问题是:您是否检查 SwingWorker 运行期间抛出的异常?这可以通过在 try/catch block 内并在 SwingWorker 完成其操作后调用 get() 来测试。

How can I make/allow this doAction() method complete properly?

不幸的是,根据您当前的代码很难判断,因为我们无法编译或运行它。如果仍然卡住,请创建并发布您的 minimal example programSSCCE .

我的主要建议:

  1. 首先,重写所有这些代码,使其严格遵循 Swing 线程规则。这是解决您问题的最大机会。了解 SwingWorkers 自动允许 PropertyChangeListener 支持,因此这可能是后台线程和 Swing 事件线程之间进行通信的好方法。
  2. 接下来一定要重构代码,使您的类成为可独立测试的小型单元,然后通过尝试让它们以您能想到的任何方式失败来最大限度地测试它们。

关于java - 为什么 doAction() 提前完成了 done() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29633930/

相关文章:

java - 如何在单击按钮时将图像发送到下一个屏幕

java - 尝试编译Java源代码(找不到主类)

java - 如何使 Android CheckBoxPreference 不可点击?

java - 在 SWING 中代表车辆

go - 如何将多个并发请求分配给 aws lambda 函数?

java - 如何从用java开发的web应用程序的http请求中检索源系统的ip地址?

java - 在浏览器上显示 java 代码的动态 Web 项目?

java - 如何在java中验证文本字段

javafx:使用任务更新 UI,然后停止执行

scala - 在 "Dispatch"库中等待超时响应