我使用sun.audio创建了一类Sound类。 (我知道它已被弃用。请不要提及。)
出于某种原因,无论我尝试过什么,线程都不会完全停止。
这是我的Sound课程:
package bob.classes;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import sun.audio.AudioData;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
import sun.audio.ContinuousAudioDataStream;
/*
* Custom class for playing audio (audio file must be in src)
*/
public class Sound {
private ContinuousAudioDataStream loop = null; //Puts music data into loop
private InputStream in = null; //Takes in music file as input
private AudioStream audioStreamMusic = null; //Takes in InputStream of music file as input
private AudioData audioData = null; //Changes AudioStream to data
private boolean loopable; //Whether the music input is meant to be looped or not
private String music; //The name of the music file
private double length; //The duration of the audio snippet in seconds
/*
* Takes in music file name and whether or not the file is loopable
*/
public Sound(String music, boolean loopable) throws IOException, UnsupportedAudioFileException {
if(music.length() < 4 || !music.substring(music.length() - 4, music.length()).equals(".wav"))
throw new IOException(music + " (Given file must be .wav)");
else if(new File(music).length() > 1000000)
throw new IOException(music + " (Given file must not be over 1 megabyte)");
this.music = System.getProperty("user.dir") + "/" + music;
this.loopable = loopable;
in = new FileInputStream(music);
audioStreamMusic = new AudioStream(in);
if(loopable) {
audioData = audioStreamMusic.getData();
loop = new ContinuousAudioDataStream(audioData);
}
AudioInputStream stream = AudioSystem.getAudioInputStream(new File(music));
AudioFormat format = stream.getFormat();
long frames = stream.getFrameLength();
length = (double) frames/format.getFrameRate();
}
/*
* Also takes in whether the file size limit should be ignored
*/
public Sound(String music, boolean loopable, boolean override) throws IOException {
if(music.length() < 4 || !music.substring(music.length() - 4, music.length()).equals(".wav"))
throw new IOException(music + " (Given file must be .wav)");
if(!override) {
if(new File(music).length() > 1000000)
throw new IOException(music + " (Given file must not be over 1 megabyte)");
}
this.music = System.getProperty("user.dir") + "/" + music;
this.loopable = loopable;
in = new FileInputStream(music);
audioStreamMusic = new AudioStream(in);
if(loopable) {
audioData = audioStreamMusic.getData();
loop = new ContinuousAudioDataStream(audioData);
}
}
/*
* Plays audio file
*/
public void play() {
if(loopable)
AudioPlayer.player.start(loop);
else {
try {
in = new FileInputStream(music);
audioStreamMusic = new AudioStream(in);
AudioPlayer.player.start(audioStreamMusic);
}
catch(IOException error) {
System.out.println(error);
}
}
}
/*
* Stops audio file if playing
*/
public void stop() {
if(loopable)
AudioPlayer.player.stop(loop);
else
AudioPlayer.player.stop(audioStreamMusic);
}
/*
* Returns a string representation of the sound, including
* the given name of the audio file as well as whether or
* not it is loopable
*/
@Override
public String toString() {
return String.format("Sound[music = %s, loopable = %b]", music, loopable);
}
public boolean equals(Sound other) {
if(music.equals(other.music))
return true;
return false;
}
/*
* Returns value of music
*/
public String getMusic() {
return music;
}
/*
* Returns value of loopable
*/
public boolean getLoopable() {
return loopable;
}
/*
* Returns value of length
*/
public double getLength() {
return length;
}
/*
* Plays group of Sounds
*/
public static Thread playGroup(Sound[] sounds, boolean loopable) throws InterruptedException {
return playGroup(new ArrayList<Sound>(Arrays.asList(sounds)), loopable);
}
/*
* Plays group of Sounds
*/
public static Thread playGroup(ArrayList<Sound> sounds, boolean loopable) throws InterruptedException {
Runnable r = new Runnable() {
@Override
public void run() {
do {
int i = 0;
try {
sounds.get(0).play();
Thread.sleep((long) (sounds.get(0).getLength() * 1000));
for(i = 1; i < sounds.size(); ++i) {
sounds.get(i).play();
sounds.get(i - 1).stop();
Thread.sleep((long) (sounds.get(i).getLength() * 1000));
}
}
catch(Exception e) {
sounds.get(i).stop();
break;
}
} while(loopable);
}
};
Thread t = new Thread(r);
t.start();
return t;
}
public static void stopGroup(Thread t) {
while(t != null && !t.isInterrupted()) {
System.out.println("Test");
t.interrupt();
}
}
}
这是我用来检查它是否正常工作的Test类:
package bob.classes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Test {
public static void main(String[] args) throws InterruptedException, IOException, UnsupportedAudioFileException {
Thread t = Sound.playGroup(new ArrayList<Sound>(Arrays.asList(new Sound("music.wav", false))), false);
Thread.sleep(1000);
Sound.stopGroup(t);
Thread t2 = Sound.playGroup(new ArrayList<Sound>(Arrays.asList(new Sound("music2.wav", false))), false);
Thread.sleep(2000);
Sound.stopGroup(t2);
//The program does not end right away here.
}
}
它运行并停止了音频,但由于某种原因它没有退出。另外,如果在发布答案时我正在做的线程停止有任何冗余/不需要,请告诉我。谢谢! :)
更新1:
我删除了isInterrupted标志,因为它不会改变任何内容,无论它是否存在。代码已相应更新。
更新2:
以下是一些更多细节:当我停止线程时,会发生中断异常。我期望我的Test类的测试用例中的线程中断立即停止程序,但是在线程似乎被中断之后仍然有一个显着的延迟。我相信Thread.sleep()只会在Thread.sleep()完成后才能完成程序。尽管如此,我认为真正的问题是声音停止后程序有明显的延迟。
答案 0 :(得分:0)
您在此处请求线程中断,并将isInterrupted
设置为true
:
public static void stopGroup(Thread t) {
while(t != null && !t.isInterrupted()) {
System.out.println("Test");
t.interrupt();
isInterrupted = true;
}
}
但是在帖子的run()
方法中,你不要退出循环:
do {
...
} while(loopable && isInterrupted);
您在isInterrupted
为true
时循环播放。所以,你永远不会退出线程。
应该是:
while(loopable && !isInterrupted);
最后,如果您使用isInterrupted
方法,则不需要使用自定义Thread.interrupt()
标记。
您可以在循环中以这种方式直接检查它:
while (!Thread.currentThread().isInterrupted())
此外,我认为您对停止线程的方式有限制
您不会在play()
方法中测试线程的中断
因此,如果它开始,你将被迫完成游戏
为了避免它,声音播放也应该是一个可以被打断的线程
您可以将interrupt()
调用链接起来。
答案 1 :(得分:0)
让我们先退一步:你的第一个和真正的问题是:你的代码比它应该的复杂10倍。我的意思是:你的while循环有两个条件变量(loopable和isInterrupted);但是,你还依赖中断该线程来阻止该循环。
我的建议:你应该退后一步,简化整个设计。应该有一个清除路径来保持循环。如果您想要停止,请在正确的位置执行loopable = false
之类的操作。
含义:通过更改控制while循环的变量来停止线程。
然后:摆脱这种非常讨厌的静态和非静态方法的混合。这只会让读者感到困惑(包括你自己)。最后,为了自己调试:添加简单的print语句以了解输入,退出的方法......