【问题标题】:Thread isn't removed after it has stopped running线程停止运行后不会被删除
【发布时间】:2014-08-07 14:47:11
【问题描述】:

我有一个在线程上运行的服务。当我需要线程停止运行时,我正在使用此代码
this.serviceThread.interrupt(); this.serviceThread = null;

有时我需要重新创建线程

this.serviceThread = new Thread() 
        {
            public void run() 
            {
                TheService.this.serviceProcessThread();
            }
        };
        this.serviceThread.start();

但是,前一个线程似乎仍然活着并且正在运行,因为它列在当前正在运行的线程列表中。每次我尝试停止并创建一个新线程时,这个列表都会不断增长。这是正常的吗?无论如何我可以摆脱那些旧线程吗?

我主要只是想知道该线程列表是否意味着它们仍然存在,如果是,我该如何删除它们。谢谢!

编辑:这就是我处理运行/停止线程的方式

public void startProcessThread()
{
    this.shutdown = false;
    this.serviceThread = new Thread() 
    {
        public void run() 
        {
            TheService.this.serviceProcessThread();
        }
    };
    this.serviceThread.start();
}
private void serviceProcessThread()
{
    do 
    {
        try 
        {
            this.getCommands();

            if (this.tasks.size() > 0)
                this.processTasks();

            if (!this.shutdown)
            {
                Thread.sleep(ServiceSleepTime);
            }
        }
        catch (Exception e) 
        {
            this.logException("serviceProcessThread", e);
        }
    } 
    while (!this.shutdown);
    if(this.serviceThread != null)
    {
        this.serviceThread.interrupt();
        this.serviceThread = null;

    }

}

【问题讨论】:

  • From What does java.lang.Thread.interrupt() do? "Thread.interrupt() 设置目标线程的中断状态/标志。然后在目标线程中运行的代码可能轮询中断状态并处理适当的。某些阻塞的方法,例如 Object.wait() 可能会立即消耗中断状态并抛出适当的异常(通常是 InterruptedException)"
  • 这听起来像是使用线程池的理想时机。
  • 所以通过调用 .interupt() 并将其设为 null,它实际上不会摆脱线程吗?我一直在寻找合适的方法来做到这一点,但我看到的只是人们中断/停止线程并创建一个新线程。
  • @Hooplehead24 您是否可以控制线程中运行的代码。如果是这样,请使用 William F. Jameson 的回答来确保它可交互的
  • 我添加了新代码供您参考。我认为我做对了,但希望有人能告诉我我是否错误地退出了它。根据我的处理方式,我不确定它是否可以完全中断。

标签: java android multithreading service thread-safety


【解决方案1】:

你必须面对的第一件事是,一个线程不能被强制停止而不会对整个Java进程产生潜在的不利影响。这就是 Java 引入线程中断机制的原因:一种通用的、合作机制来优雅地停止线程。

合作方面是关键:无论您在线程的实现代码中做什么,都必须确保它是可中断的。一个简短的清单:

  • 如果你有阻塞调用(那些在等待条件时阻止线程的调用),它们必须是可中断的(基本上,声明抛出InterruptedException);

  • 您必须正确捕获和处理InterruptedException,方法是执行任何适当的清理并使顶级run 方法返回;

  • 如果你实现了一个长时间运行的循环,你必须确保它定期检查Thread.currentThread().isInterrupted()标志,如果线程被中断则中断;

  • 如果您放弃控制任何第 3 方代码,请确保此代码是可中断的。

还请记住,Thread 作为 Java 对象的生命周期与实际执行线程无关。 Thread 只是一个句柄对象,它允许您管理底层线程,就像 File 是文件系统实体的句柄一样。将 File 引用设置为 null 不会从系统中删除文件。

更新

您的实现代码可以通过不吞下InterruptedException 来修复。

    try {
        this.getCommands();
        if (this.tasks.size() > 0)
            this.processTasks();
        if (!this.shutdown)
            Thread.sleep(ServiceSleepTime);
    }
    catch (InterruptedException e) {
        this.shutdown = true;
    }
    catch (Exception e) 
    {
        this.logException("serviceProcessThread", e);
    }

另外,这部分是多余的:

if(this.serviceThread != null)
{
    this.serviceThread.interrupt();
    this.serviceThread = null;

}

在这里,您尝试中断自己的(当前)线程。关键是线程应该被另一个线程中断。

【讨论】:

  • 所以我添加了while (!this.shutdown && !this.serviceThread.isInterrupted());,它正在正确删除这些线程。但是,我收到了InteruptedException
  • 线程必须从内部检查标志。您正在从外部(从另一个线程)检查它。
  • 就是这样!通过处理InterruptedException,它现在可以正常工作并正确摆脱线程。谢谢!
【解决方案2】:

.interrupt() 不会导致线程退出,除非您通过以下方式检查中断状态:

if (Thread.interrupted()) {
    skipRemainingActions();
}

while(!Thread.interrupted())
{
    doStuff();
}

如果线程中还有代码要运行,它会继续运行,即使你在上面调用中断

【讨论】:

    【解决方案3】:

    如果你没有同时做任何事情,你需要做的就是创建一个线程并使用处理程序向它发布任务。

    这里有很好的文章:http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/

    你也可以使用AsyncTask做同样的事情-http://developer.android.com/reference/android/os/AsyncTask.html

    如果你有任务同时运行,你可以使用 AsyncTask 的 executeOnExecutor() 方法引用-http://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor(java.util.concurrent.Executor, Params...)

    【讨论】:

      【解决方案4】:

      不是解决您的问题的方法,但是,这并没有按照您的想法做:

      Thread t = new Thread(new MyRunnableTask());
      t.start();
      t = null;
      

      t.start() 调用创建新线程。注意:我说的是“线程”,而不是“线程”。 A (big T) Thread 是一个可用于创建和管理 (little t) 线程的对象。一旦启动(小 t)线程,它就有了自己的生命。

      当您将局部变量 t 设置为 null 时,您所做的就是删除对管理(小 T)线程的(大 T)线程对象的引用。 (big T) Thread 对象不受影响:只要 (little t) 线程在运行,它将继续存在。 (little t) 线程不受影响:它将继续执行它所做的任何事情。当您将 t 设置为 null 时,唯一发生的变化是您不再可以控制新线程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-30
        • 1970-01-01
        • 1970-01-01
        • 2016-12-13
        • 1970-01-01
        • 1970-01-01
        • 2016-05-18
        相关资源
        最近更新 更多