线程中断不工作(Java Android)

线程中断不工作(Java Android),java,android,multithreading,interrupted-exception,Java,Android,Multithreading,Interrupted Exception,编辑: 我有一个线程的Runnable如下所示。它有一个我无法解决的问题:我在线程上调用interrupt()(停止它)的时候,有一半时间它实际上没有终止(没有捕获InterruptedException) 问题在于执行长网络操作的HeatingSystem.get(String)方法。我猜在该方法的某个地方,interrupted标志被重置了,但我找不到什么语句可以这样做(我没有在该方法涉及的所有类的引用中找到它,比如HttpURLConnection)。方法如下(不是我写的) 您需要将whi

编辑:

我有一个线程的Runnable如下所示。它有一个我无法解决的问题:我在线程上调用
interrupt()
(停止它)的时候,有一半时间它实际上没有终止(没有捕获
InterruptedException

问题在于执行长网络操作的
HeatingSystem.get(String)
方法。我猜在该方法的某个地方,interrupted标志被重置了,但我找不到什么语句可以这样做(我没有在该方法涉及的所有类的引用中找到它,比如
HttpURLConnection
)。方法如下(不是我写的)


您需要将while循环更改为:

// You'll need to change your while loop check to this for it to reliably stop when interrupting.
while(!Thread.currentThread().isInterrupted()) {
    try {
        final String currentTemperature = HeatingSystem.get("currentTemperature");
        mView.post(() -> showData(currentTemperature));
    } catch (ConnectException e) {
        mView.post(() -> showConnectionMessage());
        break;
    }

    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        break;
    }
}
而不是
while(true)


请注意,
Thread.interrupted()
Thread.currentThread().isInterrupted()
执行不同的操作。第一个在检查后重置中断状态。后者保持现状不变。

我过去一直在努力解决类似的问题,但我从未找到令人满意的解决方案。唯一对我有效的解决方法是引入一个易失性的布尔“stopRequested”成员变量,该变量设置为true,以中断可运行状态,并在可运行状态的while条件中进行检查,而不是线程的中断状态

关于我在这方面的经历,令人遗憾的是,我从未能够提取出一个小的可编译示例来重现这个问题。你能做到吗? 如果您不能做到这一点,我很想知道您是否确信使用了正确的mDataThread实例?
您可以通过记录其哈希代码来验证这一点…

这不是一个真正的答案,但我不知道该放在哪里。通过进一步的调试,我想我遇到了奇怪的行为,我能够在测试类中重现它。现在我很好奇,这是否真的是我怀疑的错误行为,以及其他人是否可以复制它。我希望写这篇文章作为答案是可行的

(把这个问题变成一个新问题,或者仅仅提交一份bug报告,会更好吗?)

下面是测试类,它必须在Android上运行,因为它是关于
getInputStream()
调用的,该调用在Android上的行为不同(不知道确切原因)。在Android上,
getInputStream()
在被中断时将抛出一个
InterruptedIOException
。下面的线程循环并在一秒钟后中断。因此,当异常被中断时,应该由
getInputStream()
引发异常,并且应该使用catch块捕获异常。这有时可以正常工作,但大多数情况下不会引发异常!相反,只有中断标志被重置,因此从interrupted==true更改为interrupted==false,然后被
if
捕获。
if
中的消息会为我弹出。在我看来,这是错误的行为

import java.net.HttpURLConnection;
import java.net.URL;

class InterruptTest {

InterruptTest() {
    Thread thread = new Thread(new ConnectionRunnable());
    thread.start();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {}
    thread.interrupt();
}

private class ConnectionRunnable implements Runnable {
    @Override
    public void run() {
        while (true) {
            try {
                URL url = new URL("http://www.google.com");
                HttpURLConnection connect = (HttpURLConnection) url.openConnection();

                boolean wasInterruptedBefore = Thread.currentThread().isInterrupted();
                connect.getInputStream(); // This call seems to behave odd(ly?)
                boolean wasInterruptedAfter = Thread.currentThread().isInterrupted();

                if (wasInterruptedBefore == true && wasInterruptedAfter == false) {
                    System.out.println("Wut! Interrupted changed from true to false while no InterruptedIOException or InterruptedException was thrown");
                    break;
                }
            } catch (Exception e) {
                System.out.println(e.getClass().getName() + ": " + e.getMessage());
                break;
            }
            for (int i = 0; i < 100000; i += 1) { // Crunching
                System.out.print("");
            }
        }
        System.out.println("ConnectionThread is stopped");
    }
}
}
导入java.net.HttpURLConnection;
导入java.net.URL;
类中断测试{
中断测试(){
线程线程=新线程(新连接Runnable());
thread.start();
试一试{
睡眠(1000);
}捕获(中断异常e){}
thread.interrupt();
}
私有类ConnectionRunnable实现Runnable{
@凌驾
公开募捐{
while(true){
试一试{
URL=新URL(“http://www.google.com");
HttpURLConnection connect=(HttpURLConnection)url.openConnection();
布尔值wasInterruptedBefore=Thread.currentThread().isInterrupted();
connect.getInputStream();//此调用的行为似乎很奇怪(ly?)
布尔wasInterruptedAfter=Thread.currentThread().isInterrupted();
if(wasInterruptedBefore==true&&wasInterruptedAfter==false){
System.out.println(“Wut!Interrupted在没有抛出InterruptedOException或InterruptedException时从true更改为false”);
打破
}
}捕获(例外e){
System.out.println(e.getClass().getName()+“:”+e.getMessage());
打破
}
对于(inti=0;i<100000;i+=1){//Crunching
系统输出打印(“”);
}
}
System.out.println(“连接读取已停止”);
}
}
}

只有在调用Thread.sleep()时Thread.sleep正在进行时,才会抛出InterruptedException。您还需要轮询线程的状态,以检查它是否被中断。如果是的话,停止进一步的工作。你能包括创建DataRunnable的代码以及中断它的部分吗?@包括了这些部分,感谢到目前为止的反馈。可以多次调用connect吗?生成具有相同Runnable的多个线程?我对Thread.sleep()的理解也是错误的,如果线程已经被中断,就不会抛出InterruptedException。对不起。我还认为,如果不调试代码,我将无法看到问题。在可运行代码中添加System.out.println可能值得一试,以便更好地了解需要花费的时间和执行的内容。下面是我将如何调试它。我将通过添加对
thread.currentThread().interrupt()的调用来中断线程本身
DataRunnable
run()
方法的最开始。然后我将添加一组
System.out.println(“第XX行-”+线程.currentThread().isInterrupted())语句。这样,我将缩小中断状态突然变为false的行。希望这有帮助。(或者不用打印,只需在查看
isInterrupted()
值的同时调试每一行)我已经尝试过了,但它仍然只终止了一半
@Override
public void onResume() {
    connect();
    super.onResume();
}

@Override
public void onPause() {
    Log.d(TAG, "onPause called");
    mDataThread.interrupt();
    super.onPause();
}

private void connect() {
    if (mDataThread != null && mDataThread.isAlive()) {
        Log.e(TAG, "mDataThread is alive while it shouldn't!"); // TODO: remove this for production.
    }
    setVisibleView(mLoading);
    mDataThread = new Thread(new DataRunnable());
    mDataThread.start();
}
// You'll need to change your while loop check to this for it to reliably stop when interrupting.
while(!Thread.currentThread().isInterrupted()) {
    try {
        final String currentTemperature = HeatingSystem.get("currentTemperature");
        mView.post(() -> showData(currentTemperature));
    } catch (ConnectException e) {
        mView.post(() -> showConnectionMessage());
        break;
    }

    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        break;
    }
}
import java.net.HttpURLConnection;
import java.net.URL;

class InterruptTest {

InterruptTest() {
    Thread thread = new Thread(new ConnectionRunnable());
    thread.start();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {}
    thread.interrupt();
}

private class ConnectionRunnable implements Runnable {
    @Override
    public void run() {
        while (true) {
            try {
                URL url = new URL("http://www.google.com");
                HttpURLConnection connect = (HttpURLConnection) url.openConnection();

                boolean wasInterruptedBefore = Thread.currentThread().isInterrupted();
                connect.getInputStream(); // This call seems to behave odd(ly?)
                boolean wasInterruptedAfter = Thread.currentThread().isInterrupted();

                if (wasInterruptedBefore == true && wasInterruptedAfter == false) {
                    System.out.println("Wut! Interrupted changed from true to false while no InterruptedIOException or InterruptedException was thrown");
                    break;
                }
            } catch (Exception e) {
                System.out.println(e.getClass().getName() + ": " + e.getMessage());
                break;
            }
            for (int i = 0; i < 100000; i += 1) { // Crunching
                System.out.print("");
            }
        }
        System.out.println("ConnectionThread is stopped");
    }
}
}