将Display.syncExec期间捕获的异常传播到调用线程

时间:2012-08-14 11:30:45

标签: java concurrency swt

我现在已经看过几次但仍然不确定它是否正确的模式:我需要通过Display.syncExec在SWT UI线程上调用一些代码。在UI线程中运行的代码捕获已检查的异常,并希望将此异常传播到等待的线程。模式看起来像这样:

SomeCheckedException[] exc = new SomeCheckedException[] { null };
display.syncExec(new Runnable(){
   public void run(){
      try {
         new Work().something();
      } catch (SomeCheckedException e){
         exc[0] = e;
      }
   }
});

if (exc[0] != null){
 //..
}

即使这里没有真正的并发性,我仍然认为这在可见性方面并不是真正安全的:很可能会发生UI线程存储异常,但调用线程不会看到这个并仍然读取'再次控制后访问数组时为null'。我对吗?最好的方法是捕获SWTException并通过instanceof检查其throwable字段?编辑:嗯,如果它是一个检查异常,这将不会那么容易。我需要自己从catch块中抛出SWTException。更好的解决方案?

感谢您的帮助和评论。

2 个答案:

答案 0 :(得分:1)

这是AtomicReference的一种情况:

  void foo() throws SomeCheckedException {
    final AtomicReference<SomeCheckedException> exRef = new AtomicReference<>();
    display.syncExec(new Runnable() {
      public void run() {
        try {
          new Work().something();
        } catch (SomeCheckedException e) {
          exRef.set(e);
        }
      }
    });
    SomeCheckedException ex = exRef.get();
    if (ex != null) {
      throw ex;
    }
  }

答案 1 :(得分:0)

这里有真正的并发,因为UI线程与主线程不同。这肯定会导致exc [0]为空。

如果希望主线程等到UI线程已填充,则必须同步对数组的访问权限。而你也需要时间。可能你的主线程必须反复检查,直到它被填满。或者你可以暂停它(睡眠)并让UI线程唤醒它(通知)。

编辑:等待线程的解决方案,无需通知,只需休眠几毫秒,然后检查。

//object properties
volatile Exception e = null;
volatile Exception completed = false;
...
display.syncExec(new Runnable(){
    public void run(){
        try
        {
          ...
          e = thrownException;
          ....
        } catch (...){};
        //must be after the try block:
        completed = true;
    }
...
while(! completed)
    Thread.sleep(500) //or something, lookup the javadoc
//after the while ends, you can safely access e