-
Bug
-
Resolution: Fixed
-
P3
-
jfx11, jfx13
-
x86_64
-
windows_10
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8282674 | 8u341 | Kevin Rushforth | P3 | Resolved | Fixed | b01 |
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
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
- backported by
-
JDK-8282674 Creating animated gif image from non FX App thread causes exception
- Resolved