While writing a program to MIDI with a Swing interface, I experienced a hang, such that kill -9 is required.  It is 100% reproducible by running the following program as java MidiSwingProblem hang0
import java.lang.reflect.InvocationTargetException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Synthesizer;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MidiSwingProblem {
    /**
     * JFrame never appears.  Hangs such that `kill -9` is required.
     */
    public static void hang0() throws MidiUnavailableException {
        Synthesizer synth = MidiSystem.getSynthesizer();
        synth.open();
        JFrame frame = new JFrame("MIDI Swing Hang 1");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    /**
     * JFrame never appears.  Hangs such that `kill -9` is required.
     */
    public static void hang1() throws MidiUnavailableException {
        Synthesizer synth = MidiSystem.getSynthesizer();
        synth.open();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("MIDI Swing Hang 2");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
    public static void solution0() throws MidiUnavailableException {
        // It doesn't matter whether .getSynthesizer() or new JFrame() is
        // called first.  It seems to work as long as synth.open() happens
        // after new JFrame().
        Synthesizer synth = MidiSystem.getSynthesizer();
        JFrame frame = new JFrame("MIDI Swing Solution 0?");
        synth.open();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    public static void solution1() {
        new Thread() {
            public void run() {
                try {
                    Synthesizer synth = MidiSystem.getSynthesizer();
                    synth.open();
                } catch (MidiUnavailableException noMidi) {
                    noMidi.printStackTrace();
                }
            }
        }.start();
        JFrame frame = new JFrame("MIDI Swing Solution 1?");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    public static void solution2() {
        new Thread() {
            public void run() {
                try {
                    Synthesizer synth = MidiSystem.getSynthesizer();
                    synth.open();
                } catch (MidiUnavailableException noMidi) {
                    noMidi.printStackTrace();
                }
            }
        }.start();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("MIDI Swing Solution 2?");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
    public static void main(String[] args) throws NoSuchMethodException
                                                , IllegalAccessException
                                                , InvocationTargetException {
        MidiSwingProblem.class.getMethod(args[0], new Class[0]).invoke(null);
    }
}
I assume that there is a deadlock in hang0(), and that it's my fault rather than a bug in J2SE.  (I've verified the behaviour on Java 1.7 and 1.8 on OS X.)
I have three questions:
- Taking a hint, I also tried writing it as 
hang1(), but that didn't work. Why isSwingUtilities.invokeLater()insufficient? - If I rearrange the lines (see 
solution0()) to callsynth.open()afternew JFrame(), then it works! Why? Issolution0()proper, or am I just getting lucky? It seems like a flimsy solution to me. - For good measure, I've also written 
solution1()andsolution2(), both of which do not seem to hang. Are these versions more correct thansolution0(), or are they overkill? Having thesynthobject in a separate thread makes it hard for the rest of the program to use it.