Java 在创建JFrame之前打开MIDI Synth会导致JVM挂起
在使用Swing接口向MIDI编写程序时,我遇到了挂起,因此需要使用Java 在创建JFrame之前打开MIDI Synth会导致JVM挂起,java,swing,jframe,deadlock,javax.sound.midi,Java,Swing,Jframe,Deadlock,Javax.sound.midi,在使用Swing接口向MIDI编写程序时,我遇到了挂起,因此需要使用kill-9。以java MidiSwingProblem hang0 import java.lang.reflect.InvocationTargetException; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Synthesizer; impor
kill-9
。以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);
}
}
我假设hang0()
中存在死锁,这是我的错,而不是J2SE中的错误。(我已经验证了Java1.7和OSX上的1.8的行为。)
我有三个问题:
hang1()
,但是没有用。为什么SwingUtilities.invokeLater()
不够newjframe()
之后重新排列行(请参见solution0()
)以调用synth.open()
,那么它就工作了!为什么?solution0()
是正确的,还是我只是运气好?对我来说,这似乎是一个站不住脚的解决办法solution1()
和solution2()
,这两个版本似乎都没有挂起。这些版本是否比solution0()
更为正确,或者它们是否过于苛刻?将synth
对象放在单独的线程中会使程序的其余部分很难使用它对于线程,不能保证哪个线程将首先运行 因此,我建议您使用或编写代码,以确保正确初始化 阅读更多
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Synthesizer synth = MidiSystem.getSynthesizer();
synth.open();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
JFrame frame = new JFrame("MIDI Swing Solution 1?");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
你能解释一下吗?它似乎满足了在事件分派线程中初始化
JFrame
的要求。hang1()
对我来说工作正常,但显示窗口需要时间。