2

以下代码工作正常

abstract class FunctionRunnable<V> implements Runnable {
  protected abstract V calculate();
  private V result;
  private Throwable thr;

  public synchronized final void run() {
    try {
      result = calculate();
    }
    catch (Throwable thr) {
      this.thr = thr;
    }
  }

  public synchronized final V getResult() {
    if (thr != null) {
      throw new RuntimeException(thr);
    }
    return result;
  }
}

...
final FunctionRunnable<Boolean> runnable = new FunctionRunnable<Boolean>() {
  public Boolean calculate() {
    return doCalculation();
  }

  private boolean doCalculation() {
    ...
  }
});
SwingUtilities.invokeAndWait(runnable);
final Boolean resultObj = runnable.getResult();
final boolean result = resultObj.booleanValue();

直到 Apple 发布 1.6.0_31,我们应用程序的用户有时会在最后一行获得 NPE。

您是否在代码中看到错误,或者其他人是否发现此特定 Java 更新存在类似问题?

4

3 回答 3

3

我的SSCCE:

public abstract class FunctionRunnable<V> implements Runnable {
  private V result;
  private Throwable thr;

  protected abstract V calculate();

  public synchronized final void run() {
    try { result = calculate(); } catch (Throwable thr) { this.thr = thr; }
  }

  public synchronized final V getResult() {
    if (thr != null) throw new RuntimeException(thr);
    return result;
  }

  public static void main(String[] args) throws Exception {
    final FunctionRunnable<Boolean> runnable = new FunctionRunnable<Boolean>() {
      public Boolean calculate() { return doCalculation(); }
      private boolean doCalculation() {
        try { Thread.sleep(2000); } catch (InterruptedException e) {}
        return false;
      }};
    SwingUtilities.invokeAndWait(runnable);
    System.out.println(runnable.getResult().booleanValue());
  }
}

我的Java版本:

$java -version
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3635)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode)

启动,运行 2 秒,打印false

于 2012-05-25T10:31:05.327 回答
3

如果您查看 EventQueue.invokeAndWait 的实现,您会发现它没有正确处理虚假唤醒。它调用 lock.wait() 然后不检查 runnable 是否已经真正完成执行——这意味着 invokeAndWait 可以在你的 runnable 完成执行之前返回!

出于某种原因,在 mac os 的更新 31 中,虚假唤醒已经开始以合理的频率发生,暴露了 EventQueue 中这个长期存在的错误。我不确定发生了什么变化,它不会发生在任何其他版本的 Java 中。

我们通过实现我们自己的 invokeAndWait 方法来解决这个问题,该方法使用一个简单的布尔检查来检查可运行对象的完成情况。

于 2012-06-11T23:27:42.653 回答
1

我有时会得到 NullPonterExeption.... 很奇怪

Java 版本“1.6.0_31”Java(TM) SE 运行时环境(构建 1.6.0_31-b04-415-11M3635)Java HotSpot(TM) 客户端 VM(构建 20.6-b01-415,混合模式)

于 2012-05-28T11:21:42.090 回答