正确使用ProgressMonitorDialog的取消按钮,中断线程,显示进度
Correct use of ProgressMonitorDialog's cancel button, interrupting threads, and showing progress
我已经使用 Java 几年了,但是我的线程知识是垃圾。我用 Google 搜索了很多,找到了一些关于 ProgressMonitorDialog
的一般用途的有用信息,但与我的具体情况完全不同。
我目前正在使用 ProgressMonitorDialog
作为 IRunnableWithProgress
实例的包装器,后者又是 Thread
的包装器。这工作正常,但现在我试图让取消按钮触发 运行 线程上的中断,我可以处理它以优雅地终止操作。
需要注意的一件重要事情是我有两个插件; "Data" 和 "UI"。数据插件包含所有实际工作,并且必须独立于 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();
}
}
}
}
UI:
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()
的东西来用新工作更新进度条吗?我不确定这有多可行(当我写这个问题时它突然出现在我的脑海中)所以我接下来会尝试。
这里有很多信息和问号,如果我的风格有点分散,请原谅。如果需要,我可以详细说明,但这已经是一堵文字墙了。任何信息、建议或想法表示赞赏。
在 atomic1()
和 atomic2()
之间,您确实需要检查 Thread.currentThread.isInterrupted()
以便在取消时进行清理。如果你处理了需要的东西,就不需要抛出异常。
至于进度跟踪,您可以在数据插件中创建自己的侦听器对象并允许将其传递给线程。 UI 将实例化它并将其传递给线程。这样数据就可以将进度事件传递给 UI 而无需依赖。
我已经使用 Java 几年了,但是我的线程知识是垃圾。我用 Google 搜索了很多,找到了一些关于 ProgressMonitorDialog
的一般用途的有用信息,但与我的具体情况完全不同。
我目前正在使用 ProgressMonitorDialog
作为 IRunnableWithProgress
实例的包装器,后者又是 Thread
的包装器。这工作正常,但现在我试图让取消按钮触发 运行 线程上的中断,我可以处理它以优雅地终止操作。
需要注意的一件重要事情是我有两个插件; "Data" 和 "UI"。数据插件包含所有实际工作,并且必须独立于 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();
}
}
}
}
UI:
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()
的东西来用新工作更新进度条吗?我不确定这有多可行(当我写这个问题时它突然出现在我的脑海中)所以我接下来会尝试。
这里有很多信息和问号,如果我的风格有点分散,请原谅。如果需要,我可以详细说明,但这已经是一堵文字墙了。任何信息、建议或想法表示赞赏。
在 atomic1()
和 atomic2()
之间,您确实需要检查 Thread.currentThread.isInterrupted()
以便在取消时进行清理。如果你处理了需要的东西,就不需要抛出异常。
至于进度跟踪,您可以在数据插件中创建自己的侦听器对象并允许将其传递给线程。 UI 将实例化它并将其传递给线程。这样数据就可以将进度事件传递给 UI 而无需依赖。