有没有办法等待通过asyncExec(...)提交给SWT UI线程的所有Runnables完成?
背景:
我有一个长时间运行的操作,其中包括触发事件,然后通过Display的asyncExec(...)实例方法将Runnables提交到SWT UI线程。
长时间运行操作的进度显示在ProgressMonitorDialog中,我想仅在UI线程完成Runnables后才关闭对话框。
将调用从asyncExec(...)更改为syncExec(...)不是一个选项,因为当从其他上下文触发事件时不需要后者。
答案 0 :(得分:7)
org.eclipse.swt.widgets.Display.readAndDispatch()
将处理事件队列中的事件并返回false
。但是你可能不想在处理事件时使用它。
asyncExec(*)
是一个FIFO队列(虽然OS图形事件取代了asyncExecs),因此您可以执行大部分长时间运行的op处理,然后将最终的asyncExec放入队列中:
final boolean[] done = new boolean[1];
Runnable r = new Runnable() {
public void run() {
done[0] = true;
}
};
// now wait for the event somehow. The brute force method:
while (!done[0]) {
Thread.sleep(200);
}
理论上,从你长时间运行的操作中产生的所有其他asyncExecs将在你到达最后一个时完成。
编辑:潜在的其他选项
创建自己的org.eclipse.core.runtime.jobs.Job
,然后在最后创建join()
:
public static class RefCountJob extends Job {
public RefCountJob() {
super("REF_COUNT");
}
int count = 0;
public void increment() {
count++;
}
public void decrement() {
count--;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("WAITING", IProgressMonitor.UNKNOWN);
while (count > 0) {
Thread.sleep(200);
monitor.worked(1);
}
monitor.done();
return Status.OK_STATUS;
}
}
要使用它,每次你要触发事件时递增()它,并在它们完成时让它们递减(你必须确保无论抛出什么异常它们都会减少它) - )< / p>
RefCountJob ref = new RefCountJob();
// ... do stuff, everybody increments and decrements ref
ref.increment();
// ... do more stuff
ref.increment();
// at the end of your long-running job
ref.schedule();
ref.join();
答案 1 :(得分:3)
谢谢,我最终得到了以下内容。我认为这是一个非常干净的解决方案。顺便说一句,如果我有足够的声誉,我会赞成你的答案:)
public class SWTThreadingUtils
{
public static void waitForAsyncExecsToFinish(Display display)
{
Object waitObj = new Object();
display.asyncExec(new DummyRunnable(waitObj));
synchronized (waitObj)
{
try {
waitObj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private static class DummyRunnable implements Runnable
{
private Object waitObj;
public DummyRunnable(Object waitObj)
{
this.waitObj = waitObj;
}
@Override
public void run()
{
synchronized (waitObj)
{
waitObj.notify();
}
}
}
}