【问题标题】:Correct use of ProgressMonitorDialog's cancel button, interrupting threads, and showing progress正确使用ProgressMonitorDialog的取消按钮,中断线程,显示进度
【发布时间】:2015-07-23 10:15:59
【问题描述】:

我已经使用 Java 几年了,但是我的线程知识是垃圾。我在 Google 上进行了大量搜索,发现了一些关于 ProgressMonitorDialog 的一般用法的有用信息,但与我的具体情况完全不同。

我目前使用ProgressMonitorDialog 作为IRunnableWithProgress 实例的包装器,而IRunnableWithProgress 又是Thread 的包装器。这工作正常,但现在我试图让取消按钮触发正在运行的线程上的中断,我可以处理它以优雅地终止操作。

需要注意的重要一点是我有两个插件; “数据”和“用户界面”。数据插件包含所有实际工作,并且必须独立于 UI 或任何 Eclipse 插件。 UI 插件应该尽可能的薄。

这是我目前所获得的代码的精炼版本。

数据:

public class Data {
    public static Thread createThread() {
        return new Thread() {
            @Override
            public void run() {
                Thing t = new Thing();
                t.operationA();
                t.operationB();
                t.operationC();
            }
        }
    }
}

用户界面:

public class UI {

    public void doOperation() {
        try {
            new ProgressMonitorDialog(getShell()).run(true, true, new MyOperation());
        }
        catch (Exception e) {
            e.printStatckTrace();
        }
    }

    public class MyOperation implements IRunnableWithProgress {

        @Override
        public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException {

            monitor.beginTask("Task", 2);

            try {
                Thread myThread = Data.createThread();
                myThread.start();
                monitor.worked(1);

                while (myThread.isAlive() && !monitor.isCanceled()) {}

                if (monitor.isCanceled()) {
                    myThread.interrupt();
                }

                monitor.worked(1);

            }
            finally {
                monitor.done();
            }
        }
    }

}

所以当点击取消按钮时,myThread.interrupt() 被调用。现在线程需要响应中断。 Data.createThread() 现在看起来像这样:

public static Thread createThread() {
    return new Thread() {
        @Override
        public void run() {

            Thing t = new Thing();

            t.operationA();

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationB();

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationC();

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }
        }
    }
}

像这样轮询中断状态可能相当冗长,但我看不出这会导致任何问题。

但是,如果Thing.operationA() 不是原子的,并且可以在该函数中被中断怎么办:

public class Thing {
    public void operationA() {
        atomic1();
        // How would I detect and handle a change to the interrupted state here?
        atomic2();
    }
    public void operationB() {
        // One atomic operation
    }
    public void operationC() {
        // One atomic operation
    }
}

如何检测和处理atomic1()atomic2() 之间中断状态的变化?是不是像再次轮询Thread.currentThread.isInterrupted() 一样简单?还是我需要传递一些volatile 对象来跟踪中断状态?我应该把InterruptedException 扔到某个地方吗?

我的第二个问题是关于跟踪和报告进度的。我了解应该如何使用IProgressMonitor.worked()。如前所述,我的数据线程包含 3 个操作。是否可以将该信息传递给 UI,以便我可以在 ProgressMonitorDialog 中跟踪进度?

理想情况下是这样的:

public static Thread createThread() {
    return new Thread() {
        @Override
        public void run(IProgressMonitor monitor) {

            Thing t = new Thing();

            t.operationA();

            monitor.worked(1);

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationB();

            monitor.worked(1);

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationC();

            monitor.worked(1);

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }
        }
    }
}

但是如上所述,Data 不能依赖于 Eclipse,因此在这种情况下传递 IProgressMonitor 不起作用。

我可以在我的线程中有一个变量跟踪进度,然后从 UI 线程异步调用 myThread.getProgress() 之类的东西来用新工作更新进度条吗?我不确定这是多么可行(当我写这个问题时它突然出现在我的脑海中)所以我接下来会尝试。

这里有很多信息和问号,如果我的风格有点分散,请见谅。如果需要,我可以详细说明,但这已经是一堵文字墙了。任何信息、建议或想法表示赞赏。

【问题讨论】:

    标签: java multithreading eclipse-rcp interrupt java-threads


    【解决方案1】:

    atomic1()atomic2() 之间,您确实需要检查Thread.currentThread.isInterrupted() 以在取消时进行清理。如果您处理需要的内容,则无需抛出异常。

    至于进度跟踪,您可以在 Data 插件中创建自己的侦听器对象并允许将其传递给线程。 UI 将实例化它并将其传递给线程。这样,Data 可以将进度事件传递给 UI,而无需依赖。

    【讨论】:

    • 谢谢,这是有用的信息。使用监听器来跟踪进度是个好主意!
    猜你喜欢
    • 2012-10-10
    • 2013-07-06
    • 2013-07-13
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多