线程继续在run()方法之后运行

Sim*_*son 3 java eclipse audio multithreading

我在游戏中播放声音时遇到问题.当处理声音播放的线程退出它的run方法时,它不会终止/结束/停止.我知道这是导致问题的方法,因为当我评论整个事情时,不再创建Threads.(使用JVisualVM检查).问题是退出run方法后线程不会被终止.我已经放置了一个print命令来确保它实际到达run()方法的末尾,而且它总是这样.

但是,当我检查进程时JVisualVM,线程数会因1播放的每个声音而增加.我还注意到,1每个播放的声音都增加了守护程序线程的数量.我不确定守护程序的线程是什么以及它们是如何工作的,但我试图以多种方式杀死线程.包括Thread.currentThread .stop() .destroy() .suspend() .interrupt()返回run()方法并从方法返回;

在写这条消息时,我意识到我需要关闭剪辑对象.这导致没有创建和维持额外的线程.然而,现在声音有时会消失,我不知道为什么.现在,我可以有声音并行之间进行选择,看看我的CPU得到由线程数之不尽超载或每当有一个新的声音播放的声音突然终止.

如果有人知道并行播放多个声音的不同方法或知道我的代码有什么问题,我将非常感谢任何帮助.

这是方法:

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();
    }
Run Code Online (Sandbox Code Playgroud)

Eli*_*ist 9

关于Java Threads的一些事情:

  • 线程总是在退出它的Run()方法时死掉.在你的情况下,在你调用的方法中创建了其他线程,但你的线程结束了(你可以通过命名它并查看它何时死掉来检查它).
  • 切勿使用杀死一个线程.stop(),.destroy().suspend().这些方法已弃用,不应使用.相反,你应该基本上到达Run()方法的末尾.这Thread.interrupt()是为了什么,但你必须支持通过检查Thread.isInterrupted()标志然后抛出InterruptedException并处理它来中断你的线程(有关更多详细信息,请参阅如何停止线程).
  • "守护程序线程是一个线程,当程序完成但线程仍在运行时,它不会阻止JVM退出".

关于代码的一些事情:

  • 您已经缺少许多用户提到的大括号
  • 我不太明白你想要实现什么,但do-while循环似乎是多余的.还有其他好方法可以等待声音完成播放(如果这是你的目标),并且循环不是其中之一.一个while没有运行多次的循环Sleep,无缘无故地占用你的CPU.
  • 您应该Close()( Stop())Clip如您所述,以释放系统资源.

一个带调试说明的工作示例:

尝试运行此代码,看看它是否符合您的要求.我添加了一些线程方法调用和一些System.out.prints,供您查看每一段代码发生的时间.尝试玩tryToInterruptSoundmainTimeOut看看它如何影响输出.

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 Code Online (Sandbox Code Playgroud)
  • playSound在守护进程线程上运行,因此当主(并且只有非守护进程)线程结束时,它会停止.
  • 我根据这个家伙计算了声音文件的长度,这样我就知道在多长时间内继续播放Clip.这样我可以让Thread Sleep()和不使用CPU.我使用一个额外isActive()的测试来看看它是否真的结束了,如果没有 - Sleep()再次计算剩余的时间(Sleep由于两个事实,声音可能仍然在第一个之后播放:1.长度计算不需要微秒考虑到,并且2. "你不能假设调用睡眠会在指定的时间段内暂停线程").