<AWT Dev> NPE in EventQueue.dispatchEventImpl(..)

Ludovic HOCHET lhochet at gmail.com
Sun Dec 7 19:59:26 UTC 2014


Hello,
I have an application that for the purpose of this post can be
summarised as the code that follows
(ran in an Oracle JDK 8u25/40 on Windows).
The application throws a NPE on calling
dispatchThread.stopDispatching() in EventQueue.dispatchEventImpl(..)
after a variable period of time.

After some study, by using javafx.embed.singleThread=true, the actual
dispatch is done on the JavaFX App thread.
So when the JLabel is hidden, an AWT-Shutdown is initiated,
dispatchThread.stopDispatching() is called on the JavaFX App Thread,
but after the AWT-EventQueue thread completes the handling of the
event loop and therefore wait for the next event rather than exit the
thread.
Later the AWT-Windows thread initiate another shutdown, the
AWT-EventQueue receives the event, forward it for handling, and exit
the event loop, setting the dispatchThread to null before the JavaFX
App thread calls dispatchThread.stopDispatching() which is now null
hence the NPE.

A fix [1] could be to check that the dispatchThread is not null before
calling it.
However this would not end the AWT-EventQueue thread, so a second fix
[2] could be in addition to checking for null, to repost the event
which would result in the thread termination (as well as the null
check) which was the intial intent if I get it right.
In non 'single thread' mode the change has no effect, as the
AWT-EventQueue thread exit normally before considering the reposted
event.

sample application:
package javaapplication13;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.JLabel;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingNode;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class JavaApplication13 {
  public static class FXApplication extends Application {
    @Override
    public void start(final Stage stage) throws Exception
    {
      final BorderPane p = new BorderPane();
      SwingNode n = new SwingNode();
      n.setContent(new JLabel("Hello"));
      p.setCenter(n);
      stage.setScene(new Scene(p));
      Executors.newSingleThreadScheduledExecutor().schedule(() ->
Platform.runLater(() -> p.setCenter(null)), 30, TimeUnit.SECONDS);
      stage.show();
    }
  }
  public static void main(String[] args) {
    System.out.println("start = " + Instant.now());
    Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e) -> {
      System.out.println("ex time = " + Instant.now());
      e.printStackTrace();
    });
    System.setProperty("javafx.embed.singleThread", "true");
    Application.launch(FXApplication.class, new String[]{});
  }
}

stacktrace:
java.lang.NullPointerException
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:754)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3$1.run(EventQueue.java:702)
    at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
    at com.sun.javafx.application.PlatformImpl$$Lambda$62/351018100.run(Unknown
Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
    at com.sun.javafx.application.PlatformImpl$$Lambda$61/34395512.run(Unknown
Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
    at com.sun.glass.ui.win.WinApplication$$Lambda$45/1846974874.run(Unknown
Source)
    at java.lang.Thread.run(Thread.java:745)

[1] initial fix:
diff -r 5ce8f012b3b8 src/share/classes/java/awt/EventQueue.java
--- a/src/share/classes/java/awt/EventQueue.java    Wed Nov 26
07:59:46 2014 -0800
+++ b/src/share/classes/java/awt/EventQueue.java    Sun Nov 30
17:20:50 2014 +0100
@@ -756,7 +756,10 @@
             ((TrayIcon)src).dispatchEvent(event);
         } else if (src instanceof AWTAutoShutdown) {
             if (noEvents()) {
-                dispatchThread.stopDispatching();
+                EventDispatchThread dt = dispatchThread;
+                if (dt != null) {
+                    dispatchThread.stopDispatching();
+                }
             }
         } else {
             if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {

[2] fix that will also terminate the AWT-EventQueue-0 thread:
diff -r 5ce8f012b3b8 src/share/classes/java/awt/EventQueue.java
--- a/src/share/classes/java/awt/EventQueue.java    Wed Nov 26
07:59:46 2014 -0800
+++ b/src/share/classes/java/awt/EventQueue.java    Sun Dec 07
16:53:54 2014 +0100
@@ -756,7 +756,11 @@
             ((TrayIcon)src).dispatchEvent(event);
         } else if (src instanceof AWTAutoShutdown) {
             if (noEvents()) {
-                dispatchThread.stopDispatching();
+                EventDispatchThread dt = dispatchThread;
+                if (dt != null) {
+                    dispatchThread.stopDispatching();
+                    postEvent(event);
+                }
             }
         } else {
             if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {

Thanks,
-- 
Ludovic
-----------------------------------------

"Les formes qui differencient les etres importent peu
 si leur pensees s'unissent pour batir un univers..."
 Yoko Tsuno (in 'Les titans' by Roger Leloup)
 [The shapes that differenciate beings are not important
 if their thoughts unite to build a universe]


More information about the awt-dev mailing list