invokeAndWait

Werner Lehmann lehmann at media-interactive.de
Fri Jan 4 08:51:21 PST 2013


Here's another one. Similar code, with exception propagation (wrapped 
into a runtime exception). And yes, I have deadlocked myself already 
with it :-)

>   /**
>    * Runs code on the FX thread and waits for completion. This is similar to
>    * {@link SwingUtilities#invokeAndWait(Runnable)} which is not provided
>    * by the JavaFX {@link Platform}. If the runnable throws any exception it
>    * will be wrapped into a {@code RuntimeException} thrown by this method.
>    *
>    * @param runnable the runnable to execute on the FX thread
>    * @see #runAndWait(Callable)
>    */
>   public static void runAndWait(final Runnable runnable)
>   {
>     if (Platform.isFxApplicationThread())
>       try { runnable.run(); }
>       catch (RuntimeException e) { throw new RuntimeException("Exception in runnable: " + e.getMessage(), e); } // need to wrap a runtime exception, too, so that the actual exception is always the cause of the thrown exception
>     else
>     {
>       final CountDownLatch latch = new CountDownLatch(1);
>       final MintObjectHolder<Exception> exception = new MintObjectHolder<Exception>();
>       Platform.runLater(new Runnable() {
>         @Override
>         public void run()
>         {
>           try { runnable.run(); }
>           catch (RuntimeException e) { exception.set(e); }
>           latch.countDown();
>         }
>       });
>
>       try { latch.await(); }
>       catch (InterruptedException e) { throw new RuntimeException(e); }
>
>       if (exception.get() != null)
>         throw new RuntimeException("Exception in runnable: " + exception.get().getMessage(), exception.get());
>     }
>   }

Same approach to support a callable instead of a runnable:

>   /**
>    * Runs code on the FX thread and waits for completion, returning the callable
>    * result. If the runnable throws any exception it will be wrapped into a
>    * {@code RuntimeException} thrown by this method.
>    *
>    * @param callable the callable to execute on the FX thread
>    * @see #runAndWait(Runnable)
>    */
>   public static <T> T runAndWait(final Callable<T> callable)
>   {
>     if (Platform.isFxApplicationThread())
>       try { return callable.call(); }
>       catch (Exception e) { throw new RuntimeException("Exception in callable: " + e.getMessage(), e); }
>
>     final CountDownLatch latch = new CountDownLatch(1);
>     final MintObjectHolder<T> result = new MintObjectHolder<T>();
>     final MintObjectHolder<Exception> exception = new MintObjectHolder<Exception>();
>     Platform.runLater(new Runnable() {
>       @Override
>       public void run()
>       {
>         try { result.set(callable.call()); }
>         catch (Exception e) { exception.set(e); }
>         latch.countDown();
>       }
>     });
>
>     try { latch.await(); }
>     catch (InterruptedException e) { throw new RuntimeException(e); }
>
>     if (exception.get() != null)
>       throw new RuntimeException("Exception in callable: " + exception.get().getMessage(), exception.get());
>
>     return result.get();
>   }

And another one to have the runnable called after some delay:

>   /**
>    * Runs the provided runnable after the specified delay. The runnable
>    * will be executed on the FX thread. This method can be called on
>    * any thread.
>    *
>    * @param delay the duration to wait until starting the runnable
>    * @param runnable the runnable to start after a delay
>    */
>   public static void runLater(Duration delay, final Runnable runnable)
>   {
>     final Timeline timeline = TimelineBuilder.create()
>       .keyFrames(new KeyFrame(delay))
>       .onFinished(new EventHandler<ActionEvent>() {
>         @Override public void handle(ActionEvent event) { runnable.run(); }
>       })
>       .build();
>
>     if (Platform.isFxApplicationThread())
>       timeline.play();
>     else
>       Platform.runLater(new Runnable() {
>         @Override public void run() { timeline.play(); }
>       });
>   }

The code needs the following holder class:

>   /**
>    * Holds a mutable reference. In this way the holder instance itself can be
>    * stored in a final variable and thus used in anonymous classes.
>    */
>   private static final class MintObjectHolder<T>
>   {
>     private T object;
>     public T get() { return object; }
>     public void set(T object) { this.object = object; }
>   }

Rgds
Werner


More information about the openjfx-dev mailing list