问题描述
我在游戏中播放声音时遇到问题.当处理声音播放的线程退出时,它的run方法不会终止/结束/停止.我知道正是这种方法引起了问题,因为当我注释掉整个内容时,不再创建线程. (已通过JVisualVM检查).问题在于退出运行方法后线程不会终止.我已经放置了一条打印命令,以确保它实际上到达run()方法的末尾,并且总是如此.
I have an issue with playing sound in my game. When the Thread that handles the sound playback exits it's run method it doesn't terminate/end/stop. I know it's this method that causes the problem, since when I comment the whole thing away no more Threads get created. (Checked with JVisualVM). The problem is that Threads do not get terminated after exiting the run method. I've placed a print command to ensure that it actually reaches the end of the run() method, and it always does.
但是,当我用JVisualVM
检查进程时,播放的每种声音的线程数都会增加1
.我还注意到,每播放一个声音,守护进程线程的数量就会增加1
.我不确定什么是守护线程以及它们如何工作,但是我已经尝试了多种方法来杀死线程.包括Thread.currentThread
.stop()
.destroy()
.suspend()
.interrupt()
并通过run()方法返回;
However, when I check the process with JVisualVM
, the thread count grows by 1
for each sound played. I also noted that the number of daemon threads is increased by 1
for each sound played. I am not sure what daemon threads are and how they work, but I've tried to kill the Thread in a number of ways. Including Thread.currentThread
.stop()
.destroy()
.suspend()
.interrupt()
and returning from the run()
method by return;
在编写此消息时,我意识到我需要关闭clip对象.这导致没有额外的线程被创建和维持.但是,现在声音有时消失了,我不知道为什么.现在,我可以选择并行播放声音,或者看到无数线程使我的cpu过载,或者在播放新声音时突然结束声音.
While writing this message I realised I need to close the clip object. This resulted in no extra threads being created and sustained. However, now the sound sometimes disappears and I have no idea why. Right now, I can choose between having sound in parallel and see my cpu get overloaded by an endless number of threads or have the sounds end abruptly whenever a new sound is played.
如果有人知道并行播放多种声音的另一种方法,或者知道我的代码出了什么问题,我将不胜感激.
If anyone knows of a different approach of playing multiple sounds in parallel or knows what's wrong with my code, I would greatly appreciate any help.
这是方法:
public static synchronized void playSound(final String folder, final String name) {
new Thread(new Runnable() { // the wrapper thread is unnecessary, unless it blocks on the Clip finishing, see comments
@Override
public void run() {
Clip clip = null;
AudioInputStream inputStream = null;
try{
do{
if(clip == null || inputStream == null)
clip = AudioSystem.getClip();
inputStream = AudioSystem.getAudioInputStream(SoundP.class.getResource(folder + "/" + name));
if(clip != null && !clip.isActive())
inputStream = AudioSystem.getAudioInputStream(SoundP.class.getResource(folder + "/" + name));
clip.open(inputStream);
clip.start();
}while(clip.isActive());
inputStream.close();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
推荐答案
关于Java线程的一些事情:
- 线程在退出其Run()方法时总是死掉.在您的情况下,其他线程是在您调用的方法内创建的,但是您的线程结束了(您可以通过对其进行命名来检查它并查看它何时死亡).
- 切勿使用
.stop()
,.destroy()
或.suspend()
杀死线程.这些方法已弃用,不应使用.相反,您基本上应该到达Run()方法的末尾.这就是Thread.interrupt()
的目的,但是您必须通过检查Thread.isInterrupted()
标志然后抛出InterruptedException
并对其进行处理来支持中断线程(有关更多详细信息,请参见如何停止线程). - 守护程序线程是一个线程,它不会阻止JVM在以下情况下退出程序完成,但是线程仍在运行". .
- A Thread always dies when exiting it's Run() method. In your case, other threads are created inside the methods you called, but your thread ends (you can check it by naming it and see when it dies).
- Never kill a thread using
.stop()
,.destroy()
or.suspend()
. These methods are deprecated and should not be used. Instead, you should basically get to the end of the Run() method. That's whatThread.interrupt()
is for, but you'll have to support interrupting your thread by checking theThread.isInterrupted()
flag and then throwingInterruptedException
and handling it (for more details see How to Stop a Thread). - "A daemon thread is a thread, that does not prevent the JVM from exiting when the program finishes but the thread is still running".
- 您缺少许多用户提到的大括号
- 我不太了解您要实现的目标,但是
do-while
循环似乎很多余.还有其他一些好的方法来等待声音播放完毕(如果这是您的目标),而循环不是其中之一.一个while
循环运行了很多次却没有Sleep
,这没有任何理由吞噬您的CPU. - 您应该
Close()
(和Stop()
)Clip
,如上所述,以便释放系统资源. - You have missing curly braces as mentioned by many users
- I didn't quite understand what you're trying to achieve, but the
do-while
loop seems redundant. There are other good ways to wait for the sound to finish playing (if that's your goal), and a loop is not one of them. Awhile
loop running many times withoutSleep
ing, eats up your CPU for no good reason. - You should
Close()
(andStop()
) theClip
as you mentioned, in order to free system resources. - playSound在守护程序线程上运行,以便在主线程(且只有非守护程序)结束时停止运行.
- 我已经根据这个家伙,这样我就知道了继续玩
Clip
会持续多长时间.这样,我可以让Thread
Sleep()
而不使用CPU.我使用一个附加的isActive()
作为测试,看它是否真的结束了,如果还没有,请计算剩余时间,然后再次计算Sleep()
(由于两个事实,声音可能在第一个Sleep
之后仍会播放:1 .长度计算没有考虑微秒,并且2. 您不能假设调用sleep将在指定的时间段内完全暂停线程.). - playSound runs on a daemon thread, so that when the main (and only non-daemon) Thread ends, it stops.
- I have calculated the sound file length according to this guy, so that I know in advanced how long to keep playing the
Clip
. This way I can let theThread
Sleep()
and don't use the CPU. I use an additionalisActive()
as a test to see if it really ended, and if not - calculate the remaining time andSleep()
again (the sound will probably still be playing after the firstSleep
due to two facts: 1. the length calculation doesn't take microseconds into consideration, and 2. "you cannot assume that invoking sleep will suspend the thread for precisely the time period specified").
A few things about Java Threads:
尝试运行此代码,然后查看它是否满足您的要求.我添加了一些线程方法调用和一些System.out.print
,供您查看何时发生每段代码.尝试使用tryToInterruptSound
和mainTimeOut
来查看它如何影响输出.
Try running this code, and see if it meets your requirements. I've added some thread methods calls and some System.out.print
s for you to see when every bit of code happens. Try playing with tryToInterruptSound
and mainTimeOut
to see how it effects the output.
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class PlaySound {
private static boolean tryToInterruptSound = false;
private static long mainTimeOut = 3000;
private static long startTime = System.currentTimeMillis();
public static synchronized Thread playSound(final File file) {
Thread soundThread = new Thread() {
@Override
public void run() {
try{
Clip clip = null;
AudioInputStream inputStream = null;
clip = AudioSystem.getClip();
inputStream = AudioSystem.getAudioInputStream(file);
AudioFormat format = inputStream.getFormat();
long audioFileLength = file.length();
int frameSize = format.getFrameSize();
float frameRate = format.getFrameRate();
long durationInMiliSeconds =
(long) (((float)audioFileLength / (frameSize * frameRate)) * 1000);
clip.open(inputStream);
clip.start();
System.out.println("" + (System.currentTimeMillis() - startTime) + ": sound started playing!");
Thread.sleep(durationInMiliSeconds);
while (true) {
if (!clip.isActive()) {
System.out.println("" + (System.currentTimeMillis() - startTime) + ": sound got to it's end!");
break;
}
long fPos = (long)(clip.getMicrosecondPosition() / 1000);
long left = durationInMiliSeconds - fPos;
System.out.println("" + (System.currentTimeMillis() - startTime) + ": time left: " + left);
if (left > 0) Thread.sleep(left);
}
clip.stop();
System.out.println("" + (System.currentTimeMillis() - startTime) + ": sound stoped");
clip.close();
inputStream.close();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("" + (System.currentTimeMillis() - startTime) + ": sound interrupted while playing.");
}
}
};
soundThread.setDaemon(true);
soundThread.start();
return soundThread;
}
public static void main(String[] args) {
Thread soundThread = playSound(new File("C:\\Booboo.wav"));
System.out.println("" + (System.currentTimeMillis() - startTime) + ": playSound returned, keep running the code");
try {
Thread.sleep(mainTimeOut );
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tryToInterruptSound) {
try {
soundThread.interrupt();
Thread.sleep(1);
// Sleep in order to let the interruption handling end before
// exiting the program (else the interruption could be handled
// after the main thread ends!).
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("" + (System.currentTimeMillis() - startTime) + ": End of main thread; exiting program " +
(soundThread.isAlive() ? "killing the sound deamon thread" : ""));
}
}
这篇关于在run()方法之后,线程继续运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!