线程中断不会立即停止程序

时间:2017-04-28 06:44:35

标签: java multithreading thread-sleep

我使用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()完成后才能完成程序。尽管如此,我认为真正的问题是声音停止后程序有明显的延迟。

2 个答案:

答案 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);

您在isInterruptedtrue时循环播放。所以,你永远不会退出线程。 应该是:

while(loopable && !isInterrupted);

最后,如果您使用isInterrupted方法,则不需要使用自定义Thread.interrupt()标记。
您可以在循环中以这种方式直接检查它:

while (!Thread.currentThread().isInterrupted())

此外,我认为您对停止线程的方式有限制 您不会在play()方法中测试线程的中断 因此,如果它开始,你将被迫完成游戏 为了避免它,声音播放也应该是一个可以被打断的线程 您可以将interrupt()调用链接起来。

答案 1 :(得分:0)

让我们先退一步:你的第一个和真正的问题是:你的代码比它应该的复杂10倍。我的意思是:你的while循环有两个条件变量(loopable和isInterrupted);但是,你还依赖中断该线程来阻止该循环。

我的建议:你应该退后一步,简化整个设计。应该有一个清除路径来保持循环。如果您想要停止,请在正确的位置执行loopable = false之类的操作。

含义:通过更改控制while循环的变量来停止线程。

然后:摆脱这种非常讨厌的静态和非静态方法的混合。这只会让读者感到困惑(包括你自己)。最后,为了自己调试:添加简单的print语句以了解输入,退出的方法......