线程在停止运行后不会被删除

时间:2014-08-07 14:47:12

标签: java android multithreading service thread-safety

我有一个在线程上运行的服务。当我需要线程停止运行时,我正在使用此代码
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;

    }

}

4 个答案:

答案 0 :(得分:3)

您必须面对的第一件事是不能强行停止线程而不会对整个Java进程产生潜在的负面影响。这就是为什么Java引入了线程中断的机制:一种通用的协作机制来优雅地停止线程。

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

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

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

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

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

还要记住,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;

}

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

答案 1 :(得分:0)

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

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

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

如果仍有代码在线程中运行,它将继续运行,即使你在其上调用中断

答案 2 :(得分:0)

如果您没有同时执行任何操作,则需要创建一个线程并使用处理程序向其发布任务。

这里有一篇非常好的文章: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 ...)

答案 3 :(得分:0)

不是您问题的解决方案,但是,这不符合您的想法:

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

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

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