如何在Java中启动/停止/重启一个线程?

我真的很难find一种方法来启动,停止和重新启动Java中的线程。

具体来说,我有一个类Task (当前实现Runnable )在文件Task.java 。 我的主应用程序需要能够在一个线程上启动这个任务,在需要的时候停止(杀死)线程,并且有时候杀死和重启线程。

我第一次尝试与ExecutorService但我似乎无法find一个方法,它重新启动一个任务。 当我使用.shutdownnow()任何未来调用.execute()失败,因为ExecutorService是“closures”…

那么,我怎么能做到这一点?

线程停止后,无法重新启动。 但是,没有任何东西阻止您创build和启动新线程。

选项1:创build一个新的线程,而不是尝试重新启动。

选项2:不要让线程停止,而是等待,然后当收到通知时,可以让它再次工作。 这样,线程永远不会停止,永远不需要重新启动。

根据评论编辑:

要“杀死”线程,你可以做如下的事情。

 yourThread.setIsTerminating(true); // tell the thread to stop yourThread.join(); // wait for the thread to stop 

除非在该线程中运行的代码检查并允许终止,否则不可能终止线程。

你说:“可悲的是我必须杀死/重新启动它……我没有完全控制线程的内容,对于我的情况,它需要重新启动”

如果线程的内容不允许终止它的执行,那么你不能终止该线程。

在你的文章中,你说:“我第一次尝试使用ExecutorService,但是我似乎无法find重启任务的方法,当我使用.shutdownnow()…”

如果你看看“shutdownnow”的来源,它只是运行并中断当前正在运行的线程。 这不会停止它们的执行,除非这些线程中的代码检查是否已经中断,如果是,则自行停止执行。 所以shutdownnow可能不会做你的想法。

让我来说明当我说线程的内容必须允许该线程被终止时的意思:

 myExecutor.execute(new Runnable() { public void run() { while (true) { System.out.println("running"); } } }); myExecutor.shutdownnow(); 

该线程将继续运行,即使shutdownnow被调用,因为它永远不会检查是否已被终止。 然而,这个线程将closures:

 myExecutor.execute(new Runnable() { public void run() { while (!Thread.interrupted()) { System.out.println("running"); } } }); myExecutor.shutdownnow(); 

由于这个线程检查是否被中断/closures/终止。

所以如果你想要一个可以closures的线程,你需要确保它检查是否被中断。 如果你想要一个你可以“closures”和“重新启动”的线程,你可以创build一个可以执行新任务的runnable,就像之前提到的那样。

为什么你不能closures正在运行的线程? 那么我真的撒谎,你可以调用“yourThread.stop()”,但为什么这是一个坏主意? 这个线程可以在一个同步的(或者其他关键的部分,但是我们会限制自己被这个同步关键字保护的部分)。 同步块应该在其他的线程被访问之前在它们的整体上执行并且只能被一个线程执行。 如果在同步块中间停止线程,同步块放置的保护将失效,并且程序将进入未知状态。 开发人员使同步块中的东西保持同步,如果使用threadInstance.stop(),则会破坏同步的含义,该代码的开发人员试图完成什么以及该代码的开发人员如何期望其同步块performance。

回顾java.lang.Thread

要启动或重新启动(一旦一个线程停止,你不能重新启动同一个线程,但没关系;只要创build一个新的Thread实例):

 // Create your Runnable instance Task task = new Task(...); // Start a thread and run your Runnable Thread t = new Thread(task); 

为了阻止它,在你的Task实例上有一个方法设置一个标志来告诉run方法退出; 从run返回退出线程。 如果您的调用代码在返回之前需要知道该线程已经停止,则可以使用join

 // Tell Task to stop task.setStopFlag(true); // Wait for it to do so t.join(); 

关于重新启动:即使一个Thread无法重新启动,你可以重新使用你的Runnable实例和一个新的线程,如果它有状态,并且你想保留; 来到相同的事情。 只要确保您的Runnable被devise为允许多个调用run

你不能重启一个线程,所以你最好的select是在线程被停止的时候保存对象的当前状态,当操作需要继续时,你可以使用保存的重新创build对象,然后启动新线程。

这两篇文章Swing Worker和Concurrency可以帮助您确定解决问题的最佳解决scheme。

正如Taylor L所说,由于外部调用线程可能不知道内部正在发生什么事情,因此可能会使系统处于不稳定状态,因此不能只是“停止”一个线程(通过调用一个简单的方法)你的线程。

有了这个说法,“停止”一个线程的最好方法就是让线程自己注意,让它知道什么时候停止。

如果你的任务在循环中执行某种动作,有一种方法可以暂停/重新启动处理,但是我认为它必须超出Thread API当前提供的范围。 如果它是一个单独的进程,我不知道有什么办法暂停/重新启动,而不会运行到已被弃用或不再被允许的API。

至于循环的进程,我能想到的最简单的方法是生成任务的代码实例化一个ReentrantLock,并将其传递给任务,同时保留一个引用本身。 每次任务进入循环时,都会尝试lockingReentrantLock实例,并在循环完成时解锁。 你可能想封装所有这些try / finally,确保你放开了循环结尾的锁,即使抛出一个exception。

如果您想暂停任务,只需从主代码尝试locking(因为您保留了一个参考)。 这将做的是等待循环完成,而不是让它开始另一个迭代(因为主线程持有一个锁)。 要重新启动线程,只需从主代码解锁,这将允许任务恢复其循环。

要永久地停止线程,我会使用正常的API或者在Task中留下一个标志,并在标志上设置一个setter(类似stopImmediately)。 当循环遇到这个标志的真值时,它停止处理并完成运行方法。

有时候,如果一个Thread被启动,并且它加载了一个正在处理大量的Thread / currentThread睡眠,同时忽略被中断的Exception catch的下降dynamic类,一个中断可能不足以完全退出执行。

在这种情况下,我们可以提供这些基于环路的中断:

 while(th.isAlive()){ log.trace("Still processing Internally; Sending Interrupt;"); th.interrupt(); try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } 

暂停线程和停止/终止线程是有区别的。 如果停止意味着杀死线程,那么重新启动就意味着创build一个新的线程并启动。

有杀死线程的方法(例如,你的spawner),但它们通常是不安全的。 如果你的线程经常检查一些标志,看看它是否应该继续(我假设你的线程有一些循环),并且让外部的“控制器”改变那个标志的状态,这可能会更安全。

您可以在http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html中看到更多信息;

请问为什么要杀死线程并重新启动? 为什么不直到它再次需要服务呢? Java具有完全为此目的的同步机制。 线程将处于hibernate状态,直到控制器通知它继续执行。

 You can start a thread like: Thread thread=new Thread(new Runnable() { @Override public void run() { try { //Do you task }catch (Exception ex){ ex.printStackTrace();} } }); thread.start(); To stop a Thread: thread.join();//it will kill you thread //if you want to know whether your thread is alive or dead you can use System.out.println("Thread is "+thread.isAlive()); 

build议创build一个新的线程,而不是重新启动它。

我完全不同意“不能”停止“线索”的说法。 这是一个棘手问题的近视。 为什么?

定期检查中断标志实际上是另外一种忙于等待“检查标志何时检查”的困难决定的forms。 可能非常丑陋或不可能回答。 类的线程也有“stop(Throwable throwable)”这个方法,不幸的是我不赞成我所不赞成的。 在try-catch-finally-statement中给出run()方法的正文:为什么在调用stop(new MyRuntimeException())时,任何语句(从内部)都可能抛出任何checked或uncheckedexception从外面可能不? 外面真的如此出乎意料吗? 那么如何重新抛出意外的RuntimeExceptions很less被捕获,因为它们往往是未知的? 最后,catch-clause必须处理这个例外 – 不pipe是从内部还是从外部。 最后的块可以收拾。 我希望人们再次思考这个devise问题。

我认为一个线程应该能够死亡(自行终止)或被杀死(立即终止例外)。