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 ImageRace3Old 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; } @Override 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.ToByteArgb", () -> { return ByteBgr.ToByteArgbConverter; } ), new Initializer("ByteBgr.ToByteBgr", () -> { return ByteBgr.ToByteBgrConverter; } ), new Initializer("ByteBgr.ToByteBgra", () -> { return ByteBgr.ToByteBgraConverter; } ), new Initializer("ByteBgr.ToByteBgraPre", () -> { return ByteBgr.ToByteBgraPreConverter; } ), new Initializer("ByteBgr.ToIntArgb", () -> { return ByteBgr.ToIntArgbConverter; } ), new Initializer("ByteBgr.ToIntArgbPre", () -> { return ByteBgr.ToIntArgbPreConverter; } ), new Initializer("ByteBgra.ToByteBgra", () -> { return ByteBgra.ToByteBgraConverter; } ), new Initializer("ByteBgra.ToByteBgraPre", () -> { return ByteBgra.ToByteBgraPreConverter; } ), new Initializer("ByteBgra.ToIntArgb", () -> { return ByteBgra.ToIntArgbConverter; } ), new Initializer("ByteBgra.ToIntArgbPre", () -> { return ByteBgra.ToIntArgbPreConverter; } ), new Initializer("ByteBgraPre.ToByteBgra", () -> { return ByteBgraPre.ToByteBgraConverter; } ), new Initializer("ByteBgraPre.ToByteBgraPre", () -> { return ByteBgraPre.ToByteBgraPreConverter; } ), new Initializer("ByteBgraPre.ToIntArgb", () -> { return ByteBgraPre.ToIntArgbConverter; } ), new Initializer("ByteBgraPre.ToIntArgbPre", () -> { return ByteBgraPre.ToIntArgbPreConverter; } ), new Initializer("ByteGray.ToByteBgr", () -> { return ByteGray.ToByteBgrConverter; } ), new Initializer("ByteGray.ToByteBgra", () -> { return ByteGray.ToByteBgraConverter; } ), new Initializer("ByteGray.ToByteBgraPre", () -> { return ByteGray.ToByteBgraPreConverter; } ), new Initializer("ByteGray.ToByteGray", () -> { return ByteGray.ToByteGrayConverter; } ), new Initializer("ByteGray.ToIntArgb", () -> { return ByteGray.ToIntArgbConverter; } ), new Initializer("ByteGray.ToIntArgbPre", () -> { return ByteGray.ToIntArgbPreConverter; } ), new Initializer("ByteGrayAlpha.ToByteBgra", () -> { return ByteGrayAlpha.ToByteBgra; } ), new Initializer("ByteGrayAlpha.ToByteGrayAlphaPre", () -> { return ByteGrayAlpha.ToByteGrayAlphaPre; } ), new Initializer("ByteGrayAlphaPre.ToByteBgraPre", () -> { return ByteGrayAlphaPre.ToByteBgraPre; } ), // new Initializer("ByteIndexed"), // Has no .getter new Initializer("ByteRgb.ToByteArgb", () -> { return ByteRgb.ToByteArgbConverter; } ), new Initializer("ByteRgb.ToByteBgr", () -> { return ByteRgb.ToByteBgrConverter; } ), new Initializer("ByteRgb.ToByteBgra", () -> { return ByteRgb.ToByteBgraConverter; } ), new Initializer("ByteRgb.ToByteBgraPre", () -> { return ByteRgb.ToByteBgraPreConverter; } ), new Initializer("ByteRgb.ToIntArgb", () -> { return ByteRgb.ToIntArgbConverter; } ), new Initializer("ByteRgb.ToIntArgbPre", () -> { return ByteRgb.ToIntArgbPreConverter; } ), new Initializer("ByteRgba.ToByteBgra", () -> { return ByteRgba.ToByteBgraConverter; } ), new Initializer("ByteRgba.ToByteRgba", () -> { return ByteRgba.ToByteRgbaConverter; } ), new Initializer("IntArgb.ToByteBgra", () -> { return IntArgb.ToByteBgraConverter; } ), new Initializer("IntArgb.ToByteBgraPre", () -> { return IntArgb.ToByteBgraPreConverter; } ), new Initializer("IntArgb.ToIntArgb", () -> { return IntArgb.ToIntArgbConverter; } ), new Initializer("IntArgb.ToIntArgbPre", () -> { return IntArgb.ToIntArgbPreConverter; } ), new Initializer("IntArgbPre.ToByteBgra", () -> { return IntArgbPre.ToByteBgraConverter; } ), new Initializer("IntArgbPre.ToByteBgraPre", () -> { return IntArgbPre.ToByteBgraPreConverter; } ), new Initializer("IntArgbPre.ToIntArgb", () -> { return IntArgbPre.ToIntArgbConverter; } ), new Initializer("IntArgbPre.ToIntArgbPre", () -> { return IntArgbPre.ToIntArgbPreConverter; } ), }; // 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); } }