import com.sun.javafx.image.impl.ByteArgb; import com.sun.javafx.image.impl.ByteBgr; import com.sun.javafx.image.impl.ByteBgra; import com.sun.javafx.image.impl.ByteBgraPre; import com.sun.javafx.image.impl.ByteGray; import com.sun.javafx.image.impl.ByteGrayAlpha; import com.sun.javafx.image.impl.ByteGrayAlphaPre; import com.sun.javafx.image.impl.ByteRgb; import com.sun.javafx.image.impl.ByteRgba; import com.sun.javafx.image.impl.IntArgb; import com.sun.javafx.image.impl.IntArgbPre; import javafx.application.Application; import javafx.application.Platform; import javafx.stage.Stage; public class ImageRace2 extends Application { static volatile boolean ready = false; static interface InitProc { public Object get(); } static class Initializer extends Thread { private final InitProc init; private volatile boolean running; public Initializer(String classname, InitProc r) { super(classname+" Initializer"); this.init = r; } public boolean isRunning() { return running; } public void run() { System.err.println(getName()+" started"); running = true; while (!ready) {} init.get(); System.err.println(getName()+" done"); } } @Override public void start(Stage stage) { Initializer threads[] = { new Initializer("ByteArgb", () -> { return ByteArgb.getter; } ), new Initializer("ByteBgr", () -> { return ByteBgr.getter; } ), new Initializer("ByteBgra", () -> { return ByteBgra.getter; } ), new Initializer("ByteBgraPre", () -> { return ByteBgraPre.getter; } ), new Initializer("ByteGray", () -> { return ByteGray.getter; } ), new Initializer("ByteGrayAlpha", () -> { return ByteGrayAlpha.getter; } ), new Initializer("ByteGrayAlphaPre", () -> { return ByteGrayAlphaPre.getter; } ), // new Initializer("ByteIndexed"), // Has no .getter new Initializer("ByteRgb", () -> { return ByteRgb.getter; } ), new Initializer("ByteRgba", () -> { return ByteRgba.getter; } ), new Initializer("IntArgb", () -> { return IntArgb.getter; } ), new Initializer("IntArgbPre", () -> { return IntArgbPre.getter; } ) }; // If we initialize either of the ByteBgra* classes from the main thread // then there is no deadlock. Similarly, if we run thread 1 and thread 2 // serially there is no deadlock. // This will workaround the issue // try { // Class.forName("com.sun.javafx.image.impl.ByteBgra"); // } catch (ClassNotFoundException ignore) { // } for (Initializer i : threads) { i.start(); while (!i.isRunning()) {} } System.err.println("[main] signal the threads to proceed"); try { Thread.sleep(100); } catch (InterruptedException ex) {} ready = true; try { Thread.sleep(100); for (Initializer i : threads) { i.join(); } } catch (InterruptedException ex) {} Platform.exit(); } public static void main(String[] args) { Application.launch(args); } }