java - run() 方法后线程继续运行

标签 java eclipse multithreading audio

我在游戏中播放声音时遇到问题。当处理声音播放的线程退出它的运行方法时,它不会终止/结束/停止。我知道是这种方法导致了问题,因为当我将整个事情都注释掉时,不再创建线程。 (使用 JVisualVM 检查)。问题是线程在退出 run 方法后不会终止。我已经放置了一个打印命令以确保它确实到达了 run() 方法的末尾,而且它始终如此。

但是,当我使用 JVisualVM 检查进程时,线程计数会随着每个播放的声音增加 1。我还注意到,每播放一个声音,守护线程的数量就会增加 1。我不确定守护线程是什么以及它们是如何工作的,但我已经尝试以多种方式终止线程。包括Thread.currentThread .stop() .destroy() .suspend() .interrupt( ) 并通过return从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();
    }

最佳答案

关于 Java 线程的一些事情:

关于您的代码的一些事情:

  • 正如许多用户提到的那样,您缺少花括号
  • 我不太明白您要实现的目标,但是 do-while 循环似乎是多余的。还有其他等待声音完成播放的好方法(如果这是您的目标),循环不是其中之一。一个 while 循环在没有 Sleeping 的情况下运行多次,无缘无故地占用你的 CPU。
  • 您应该Close()(Stop())您提到的Clip,以便释放系统资源。

带有调试说明的工作示例:

尝试运行这段代码,看看它是否满足您的要求。我添加了一些线程方法调用和一些 System.out.print 供您查看每一位代码何时发生。尝试使用 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" : ""));
    }
}
  • playSound 在守护线程上运行,因此当主线程(也是唯一的非守护线程)结束时,它会停止。
  • 我根据this guy计算出声音文件的长度,这样我就可以提前知道要继续播放 Clip 多长时间。这样我就可以让 Thread Sleep() 并且不使用 CPU。我使用额外的 isActive() 作为测试,看看它是否真的结束了,如果没有 - 计算剩余时间并再次 Sleep() (声音可能仍然在第一个 Sleep 之后播放是因为两个事实:1. 长度计算不考虑微秒,以及 2. "you cannot assume that invoking sleep will suspend the thread for precisely the time period specified" ).

关于java - run() 方法后线程继续运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16762353/

相关文章:

java - 如何通过 Java 中的随机过程生成对象的唯一值

java - 在 Jackson 的 ObjectMapper 中动态启用/禁用 UNWRAP_ROOT_VALUE 和 WRAP_ROOT_VALUE?

java - 在 JSP 中,如何动态设置 contentType?

Java 库文件错误

java - 仅由一个线程写入的 volatile boolean 开关是线程安全的吗?

java - Hadoop映射器构造函数,何时以及如何?

java - Android Manifest- Intent 过滤器和 Activity

java - Eclipse 警告 Uncaught Error

java - 如何计算多线程程序的运行时间?

java - 停止 DatagramSocket 线程