如何从另一种方法停止/中断正在运行的线程?

时间:2016-03-16 22:51:26

标签: java android runnable

我是Android和Java开发的初学者,我目前正在尝试制作一个节拍器。 在让声音播放工作之后我遇到的第一个问题是,每当节拍器播放应用程序时都会停止响应 - 当我了解线程以及我应该如何使用新线程进行音频播放时。

创建一个新线程帮助,现在应用程序运行正常,但我无法让线程停止/中断。我已经阅读了50篇关于线程和中断的文章,我无法弄明白。

这是我的'播放器'类代码,我大部分都是从另一个Stack Overflow帖子中复制过来的(我尝试了无数其他方法和变体,但都没有用):

package com.example.t.firstapp;

import android.util.Log;

public class Player implements Runnable {

    Thread backgroundThread;
    Metronome m;


    public void start() {
        if (backgroundThread == null) {
            backgroundThread = new Thread(this);
            m = new Metronome();
            backgroundThread.start();
        }
    }

    public void stop() {
        if (backgroundThread != null) {
            backgroundThread.interrupt();
        }
    }

    public void run() {
        try {
            Log.i("a", "Thread starting.");
            while (!backgroundThread.isInterrupted()) {
                m.play();
            }
            Log.i("b", "Thread stopping.");
            throw new InterruptedException(); // ???
        } catch (InterruptedException ex) {
            // important you respond to the InterruptedException and stop processing
            // when its thrown!  Notice this is outside the while loop.
            Log.i("c", "Thread shutting down as it was requested to stop.");
        } finally {
            backgroundThread = null;
        }

    }
}

注意标有" ???"的行。我自己添加了一个,因为否则" catch(InterruptedException ex)"返回错误。 以下是我的MainActivity类中的相关代码:

public class MainActivity extends AppCompatActivity {

...

public Player p;

...
    public void play() {
        p = new Player();
        p.start();
    }
    public void stop() {
        p.stop();
    }
}

调用p.stop();从方法中停止'实际上并没有做任何事情。这是我被卡住的地方。如果我在启动线程后立即调用p.stop(),如下所示:

public void play() {
    p = new Player();
    p.start();
    p.stop();
}

然后它工作,我看到来自Player类的所有相关日志消息。当我从我的“停止”中调用它时,为什么没有p.stop()工作?方法?是因为我是用不同的方法调用它,还是因为我没有立即调用它?

任何帮助都会非常感激,因为这非常令人沮丧。我一直在研究和练习Android开发仅一周,但过去5天我没有做任何事情,但试图解决这个问题。感谢

1 个答案:

答案 0 :(得分:2)

你误解了中断的概念。中断不是迫使线程停止的一种神奇方式,而是仅适用于有中断支持的方法 - 比如睡觉。

查看Thread#interrupt() API,其中列出了中断支持的方法:

  

如果在调用wait() t类的wait(long)wait(long, int)Objec方法或join()方法时阻止此线程,join(long)join(long, int)sleep(long)sleep(long, int)这个类的方法,然后它的中断状态将被清除,它将收到InterruptedException。< / p>      

如果此线程在可中断通道的I / O操作中被阻止,则通道将关闭,线程的中断状态将被设置,并且线程将收到ClosedByInterruptException

     

如果此线程在Selector中被阻止,则线程的中断状态将被设置,并且它将立即从选择操作返回,可能具有非零值,就像选择器& #39;唤醒方法被调用。

     

如果以前的条件都不成立,那么将设​​置此线程的中断状态。

通过检测中断状态,您可以通过中断支持很好地实现自己的方法。

现在让我们看看我们如何解决您的问题。

根据你的评论,m.play()没有返回,这意味着,一旦m.play()被调用,while永远不会检查线程是否被中断;反过来它永远不会停止,因为m.play() 并未实现以支持中断。这也应该解释为什么编译器抱怨没有人抛出InterruptedException。 (如果立即中断它起作用的原因是中断状态在到达while之前改变了......想一想。)

现在,我认为,如果您致电m.stop()m.play() 返回,成功重新检查线程中断。正如评论中所提到的那样,这就是它起作用的原因。

但是看,没有真正使用中断线程 - 因为你要做的就是调用m.stop()并释放m.play(),只是玩并等待返回 - 这意味着停止已被召唤。与while循环相同,将其全部删除。

public void run() {
    Log.i("a", "Thread starting.");

    m.play(); // blocks till stopped from some other thread...

    Log.i("b", "Thread stopping.");
    Log.i("c", "Thread shutting down as it was requested to stop.");

    backgroundThread = null;
}

我可能会看到使用while和中断的情况,如果m.play()可能早于调用m.stop()(例如,通过某种例外)返回,并且您希望重启节拍器直到调用停止;然后一个循环可能正在拯救,并且中断可能通过调用m.stop()发出信号表明它实际上已停止。

public void run() {
    Log.i("a", "Thread starting.");
    while (!backgroundThread.isInterrupted()) {
        m.play();
        if(!backgroundThread.isInterrupted())
            Log.i("b", "Stopped by exception, restarting....");
    }

    Log.i("c", "Thread stopping.");
    Log.i("d", "Thread shutting down as it was requested to stop.");

    backgroundThread = null;
}