在使用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;
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中的错误。 (我已经验证了OS X上Java 1.7和1.8的行为。)
我有三个问题:
hang1()
,但这并不奏效。为什么SwingUtilities.invokeLater()
不足?solution0()
之后重新排列这些行(请参阅synth.open()
)以致电new JFrame()
,那么它是有效的!为什么? solution0()
是否合适,或者我是否幸运?这对我来说似乎是一个脆弱的解决方案。solution1()
和solution2()
,两者似乎都没有挂起。这些版本是否比solution0()
更正确,还是过度杀伤?将synth
对象放在一个单独的线程中会使程序的其余部分难以使用它。答案 0 :(得分:4)
如果是线程,则无法保证首先运行哪个线程。
因此,我建议您在SwingUtilities.invokeLater()或EventQueue.invokeLater()中编写代码,以确保EDT已正确初始化。
了解更多
示例代码:
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);
}
});