简体   繁体   中英

Simple CompletableFuture.supplyAsync() leads to IllegalMonitorStateException error

I'm trying this in java8:

  public static void main(String[] args) throws Exception {
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(
      () -> { return 911; });
    future.whenComplete(
      (result, error) -> {
        System.out.println("Alarm:" + result);
        error.printStackTrace();
      }
    );
    future.wait();
  }

Upon running, I got this output:

Alarm:911
[WARNING]
java.lang.IllegalMonitorStateException
    at java.lang.Object.wait (Native Method)
    at java.lang.Object.wait (Object.java:502)
    at mygroup.UseCompletableFuture.main (UseCompletableFuture.java:15)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:254)
    at java.lang.Thread.run (Thread.java:748)

Is the "error" information expected? Did I miss anything in my code snippet?

The wait method derives from the Object class. If you need to use it, you need to monitor the object.

In your case, you should not need to monitor, but you need to 'wait for the completable future to complete'. In this case you need to switch from wait to get method.

The exception whose stack trace is shown is thrown by future.wait() and is not related to the error argument of the second CompleableFuture . It occurs because wait() requires the thread invoking it to be holding the object's monitor. See this for a description of what it means for a thread to be owner of the object's monitor. Your code basically has to be within a synchronized block in order to be able to call wait() or notify() . You probably intended to call get() , the wait()/notify() methods are generic synchronization methods inherited by Object and have been there since the beginning of Java.

As for the error parameter, it is indeed null, because the first stage completes normally. Hence, the line error.printStackTrace() should thrown a NPE. However, your code simply does not handle. It is thrown in the async thread that executes the stage, and remains silent. See this post in relation to this behavior.

I suspect you want to call the get() method on the future. First you should assign the second stage to a variable ( future is still referencing the first stage):

future = future.whenComplete(
      (result, error) -> {
        System.out.println("Alarm:" + result);
        System.out.println(error);
        error.printStackTrace();
      }
);

Then you could call get() on it, which allows you to handle an ExecutionException which will wrap the NPE occurring in the second stage:

try {
    result = future.get();
    System.out.println(result);
} catch (InterruptedException e) {
    ...
} catch (ExecutionException e) {
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM