我已经使用Java几年了,但是我的线程知识很垃圾。我已经在Google上进行了大量搜索,发现了一些有关ProgressMonitorDialog
常规用法的良好信息,但与我的实际情况完全不同。
我目前正在使用ProgressMonitorDialog
作为IRunnableWithProgress
实例的包装,而后者又是Thread
的包装。这可以正常工作,但是现在我试图使“取消”按钮在正在运行的线程上触发中断,我可以处理该中断以优雅地终止操作。
需要注意的重要一件事是我有两个插件。 “数据”和“ 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();
}
}
}
}
用户界面:
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;
}
}
}
}
但是,如上所述,数据不能依赖Eclipse,因此在这种情况下,传递
IProgressMonitor
无效。我可以在线程中跟踪进度的变量,然后从UI线程异步调用
myThread.getProgress()
之类的东西来用新工作更新进度条吗?我不确定这是多么可行(在我撰写此问题时突然出现在我的脑海中),所以我将在下一个尝试。这里有很多信息和问号,对不起,如果我的风格有点分散。如果需要,我可以详细说明,但这已经是一堵墙了。任何信息,建议或想法表示赞赏。
最佳答案
在atomic1()
和atomic2()
之间,您确实需要检查Thread.currentThread.isInterrupted()
以进行清除以防取消。如果您需要处理什么,则无需引发异常。
至于进度跟踪,您可以在Data插件中创建自己的侦听器对象,并允许将其传递给线程。 UI将实例化它并将其传递给线程。这样,数据可以将进度事件传递给UI,而无需依赖。