Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8222211

Creating animated gif image from non FX App thread causes exception

    Details

    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      windows_10

      Description

      ADDITIONAL SYSTEM INFORMATION :
      I have replicated this on Java 8u191 and Java 11.0.2 with JavaFX 11.0.2

      A DESCRIPTION OF THE PROBLEM :
      Creating animated javafx.scene.image.Image from 2 threads causes ArrayIndexOutOfBoundsException exception.
      Issue is caused by the fact that animated Images adds pulse listener without checking if it's invoked from fx thread, so there might be a case where two separate threads breaks pulse listener array in "AbstractMasterTimer" called "receivers".

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Provide all dependencies to attached code (javafx-controls) and "cat.gif" as a resource, which might be any gif animated image with more than 1 frame.
      2. Run the code.
      3. Exception should be shown in console window
      Exception might not occur on every application start, but on 8/10 occurs in a different way.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Toolkit#checkFxUserThread() is invoked while retrieving AbstractMasterTimer from Toolkit#getMasterTimer() and if Image is created on separate thread, an exception is thrown
      ACTUAL -
      ArrayIndexOutOfBoundsException exception is thrown

      ---------- BEGIN SOURCE ----------
      package com.example;

      import java.io.IOException;
      import java.io.InputStream;
      import java.util.concurrent.CountDownLatch;

      import com.sun.javafx.tk.Toolkit;
      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.image.Image;
      import javafx.scene.image.ImageView;
      import javafx.scene.layout.BorderPane;
      import javafx.stage.Stage;

      public class SimpleMain
      {

          public static void main( String[] args ) throws Exception
          {
              final int threadNo = 4;
              final CountDownLatch latch = new CountDownLatch( threadNo + 1 );
              for( int i = 0; i < threadNo; i++ )
              {
                  new Thread( () -> {
                      latch.countDown();
                      try
                      {
                          latch.await();
                      }
                      catch( InterruptedException aE )
                      {
                          aE.printStackTrace();
                      }
                      try
                      {
                          createImage();
                      }
                      catch( Exception aE )
                      {
                          aE.printStackTrace();
                      }
                  } ).start();
              }
              Toolkit.getToolkit().getMasterTimer().addPulseReceiver( now -> {
                  latch.countDown();
              } );
              Application.launch( MainFx.class, args );
              latch.await();
          }

          private static Image createImage()
          {
              try (final InputStream catResource = SimpleMain.class.getResourceAsStream( "/cat.gif" ))
              {
                  return new Image( catResource );
              }
              catch( IOException aE )
              {
                  throw new IllegalStateException( aE );
              }
          }

          public static class MainFx extends Application
          {

              @Override
              public void start( final Stage primaryStage ) throws Exception
              {
                  System.err.println( Runtime.version().toString() );
                  System.err.println( System.getProperty( "javafx.version" ) );
                  System.err.println( System.getProperty( "javafx.runtime.version" ) );
                  final int threadNo = 4;
                  final CountDownLatch latch = new CountDownLatch( threadNo + 1 );
                  for( int i = 0; i < threadNo; i++ )
                  {
                      new Thread( () -> {
                          latch.countDown();
                          try
                          {
                              latch.await();
                          }
                          catch( InterruptedException aE )
                          {
                              aE.printStackTrace();
                          }
                          try
                          {
                              createImage();
                          }
                          catch( Exception aE )
                          {
                              aE.printStackTrace();
                          }
                      } ).start();
                  }
                  latch.countDown();
                  latch.await();
                  final Image catImage = createImage();
                  final Scene aScene = new Scene( new BorderPane( new ImageView( catImage ) ), 800, 600 );
                  primaryStage.setScene( aScene );
                  primaryStage.show();
              }

          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Do not create animated images on non-FX thread

      FREQUENCY : often


        Attachments

          Activity

            People

            • Assignee:
              arapte Ambarish Rapte
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: