【问题标题】:Thread not interrupting even though I'm calling thread.interrupt()即使我正在调用 thread.interrupt(),线程也不会中断
【发布时间】:2012-03-20 16:55:49
【问题描述】:

我正在学习如何在 Android 中使用线程,为此我制作了一个播放一系列音符的小应用程序。这个想法是有一个开始按钮和一个结束按钮,并且(显然)如果你按下开始按钮,它就会开始播放音乐,如果你按下结束按钮,它就会停止。开始按钮工作得很好,但问题是结束按钮没有。我很难弄清楚原因,所以也许你们中的一些人可以帮助我。这是代码:

public class PressAndPlay extends Activity {
    private volatile Thread initBkgdThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button startButton = (Button) findViewById(R.id.trigger);
        startButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {

                // create thread
                initBkgdThread = new Thread(new Runnable() {
                    public void run() {
                        play_music();
                    }
                });
                initBkgdThread.start();
            }
        });

        Button endButton = (Button) findViewById(R.id.end);
        endButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                end_music();
            }
        });
    }

    int[] notes = {R.raw.c5, R.raw.b4, R.raw.a4, R.raw.g4};
    int NOTE_DURATION = 400;
    MediaPlayer m_mediaPlayer;

    private void play_music() {
        for(int ii=0; ii<12; ii++) {
            //check to ensure main activity is not paused
            if(!paused) {
                if (m_mediaPlayer != null) {m_mediaPlayer.release();}
                m_mediaPlayer = MediaPlayer.create(this, notes[ii%4]);
                m_mediaPlayer.start();
                try {
                    Thread.sleep(NOTE_DURATION);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void end_music() {
         if(initBkgdThread != null) {
             initBkgdThread.interrupt();
             initBkgdThread = null;
         }
    }

    boolean paused = false;
    @Override
    protected void onPause() {
        paused = true;
        super.onPause();
    }
    @Override
    protected void onResume() {
        super.onResume();
        paused = false;
    }
}

【问题讨论】:

    标签: java android multithreading background runnable


    【解决方案1】:

    您正在播放线程上调用interrupt(),但当时它可能正在sleep 中等待。这将捕获睡眠以抛出InterruptedException。您需要捕获该异常退出循环以停止播放:

    try {
        Thread.sleep(NOTE_DURATION);
    } catch (InterruptedException e) {
        // XXX need to stop playing here, maybe return or break?
        return;
    }
    

    由于interrupt() 也可以在不同的时间出现,您需要测试中断状态并退出循环:

    if (!paused && !Thread.currentThread().isInterrupted()) {
       ...
    

    另外,两个线程之间共享的所有变量要么需要synchronized,要么标记为volatilepaused 标志在这里应该是 volatile

    volatile boolean paused = false
    

    最后,为了后代,当你捕获InterruptedException时,它会清除线程的中断状态。通常最好立即在线程上设置中断标志,以便其他人可以对其进行测试:

    try {
        Thread.sleep(NOTE_DURATION);
    } catch (InterruptedException e) {
        // re-establish the interrupt condition
        Thread.currentThread.interrupt();
        ...
    }
    

    【讨论】:

    • 最后一点没看懂,执行return;和重新建立中断条件有什么区别。
    • 每当你捕捉到InterruptedException,线程上的中断状态就会被清除,所以你应该重新中断线程。这是一个重要的模式,因此如果您的代码在库中,调用者将收到线程被中断的通知。这只是我经常提到的一种模式@MuhammedRefaat。
    • 太好了,如果中断时代码处理会发生变化,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2020-03-13
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多