簡體   English   中英

線程繼續在run()方法之后運行

[英]Thread continues to run after run() method

我在游戲中播放聲音時遇到問題。 當處理聲音播放的線程退出它的run方法時,它不會終止/結束/停止。 我知道這是導致問題的方法,因為當我評論整個事情時,不再創建Threads。 (使用JVisualVM檢查)。 問題是退出run方法后線程不會被終止。 我已經放置了一個print命令來確保它實際到達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 Threads的一些事情:

  • 線程總是在退出它的Run()方法時死掉。 在你的情況下,在你調用的方法中創建了其他線程,但是你的線程結束了(你可以通過命名它並查看它何時死掉來檢查它)。
  • 永遠不要使用.stop() .destroy().suspend()來殺死一個線程。 這些方法已棄用,不應使用。 相反,你應該基本上到達Run()方法的末尾。 這就是Thread.interrupt()的用途,但你必須支持通過檢查Thread.isInterrupted()標志來中斷你的線程,然后拋出InterruptedException並處理它(有關更多詳細信息,請參閱如何停止線程 )。
  • “守護程序線程是一個線程,當程序完成但線程仍在運行時,它不會阻止JVM退出”

關於代碼的一些事情:

  • 您已經缺少許多用戶提到的大括號
  • 我不太明白你想要實現什么,但是do-while循環似乎是多余的。 還有其他好方法可以等待聲音完成播放(如果這是你的目標),並且循環不是其中之一。 while沒有Sleep情況下運行多次的while循環,無緣無故地耗盡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在守護進程線程上運行,因此當主(並且只有非守護進程)線程結束時,它會停止。
  • 我根據這個家伙計算了聲音文件的長度,這樣我就知道繼續播放Clip有多長。 這樣我可以讓Thread Sleep()並不使用CPU。 我使用額外的isActive()作為測試來查看它是否真的結束了,如果沒有 - 再次計算剩余時間和Sleep() (由於兩個事實,聲音可能仍然在第一次Sleep后播放:1。長度計算不需要考慮微秒,並且2. “你不能假設調用sleep會在指定的時間段內暫停線程” )。

你的代碼就是這個

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();
}

if語句僅適用於它們之后的第一個命令。 第二個'if'是無意義的,因為語句已經運行了。 它看起來像每次你循環播放剪輯是'.start'再次產生另一個線程,無論剪輯是否有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM