我很难找到一种在Java中启动,停止和重启线程的方法。
具体来说,我在文件Task
中有一个类Runnable
(目前实现Task.java
)。我的主应用程序需要能够在一个线程上启动此任务,在需要时停止(终止)该线程,有时甚至是KILL&重新启动线程...
我的第一次尝试是ExecutorService
,但我似乎找不到重启任务的方法。当我.shutdownnow()
使用.execute()
以后,对ExecutorService
的任何调用都会失败,因为{{1}}是“关闭”...
那么,我怎么能做到这一点?
答案 0 :(得分:41)
一旦线程停止,您就无法重新启动它。但是,没有什么可以阻止您创建和启动新线程。
选项1:创建一个新线程,而不是尝试重新启动。
选项2:而不是让线程停止,让它等待,然后当它收到通知时,你可以让它再次工作。这样线程永远不会停止,永远不需要重新启动。
根据评论进行修改:
要“杀死”线程,您可以执行以下操作。
yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop
答案 1 :(得分:9)
除非在该线程中运行的代码检查并允许终止,否则无法终止线程。
你说:“可悲的是,我必须杀死/重启它...我没有完全控制线程的内容,对于我的情况,它需要重新启动”
如果线程的内容不允许终止其exectuion,那么你就无法终止该线程。
在你的帖子中你说:“我的第一次尝试是使用ExecutorService,但我似乎找不到重启任务的方法。当我使用.shutdownnow()......”
如果查看“shutdownnow”的来源,它只会运行并中断当前正在运行的线程。这不会停止执行,除非这些线程中的代码检查它是否已被打乱,如果是,则自行停止执行。因此,shutdownnow可能没有按照你的想法行事。
让我说明当我说线程的内容必须允许终止该线程时我的意思:
myExecutor.execute(new Runnable() {
public void run() {
while (true) {
System.out.println("running");
}
}
});
myExecutor.shutdownnow();
该线程将继续运行,即使调用了shutdownnow,因为它永远不会检查它是否已被终止。但是,该线程将关闭:
myExecutor.execute(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
System.out.println("running");
}
}
});
myExecutor.shutdownnow();
由于该线程检查它是否已被中断/关闭/终止。
因此,如果您想要一个可以关闭的线程,您需要确保它检查它是否已被中断。如果你想要一个可以“关闭”和“重启”的线程,你可以制作一个可以执行新任务的runnable,如前所述。
为什么不关闭正在运行的线程?好吧,我实际上撒谎,你可以调用“yourThread.stop()”,但为什么这是一个坏主意?当你停止它时,该线程可能处于同步(或其他关键部分,但我们将限制在这里由同步关键字保护的部分)部分代码中。 synch块应该在它们的整数中执行,并且在被其他一些线程访问之前只能由一个线程执行。如果在同步块中间停止某个线程,则synch块保护的保护将失效,程序将进入未知状态。开发人员将内容置于同步块中以保持同步,如果使用threadInstance.stop(),则会破坏同步的含义,该代码的开发人员试图完成的内容以及该代码的开发人员如何期望他的同步块表现。
答案 2 :(得分:8)
要启动或重新启动(一旦线程停止,您就无法重新启动相同的线程,但这无关紧要;只需创建一个新的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
设计为允许多次调用run
。
答案 3 :(得分:4)
您无法重新启动线程,因此您最好的选择是在线程停止时保存对象的当前状态,并且当操作需要在该对象上继续时,您可以使用保存的方式重新创建该对象,然后启动新线程。
这两篇文章Swing Worker和Concurrency可以帮助您确定问题的最佳解决方案。
答案 4 :(得分:2)
正如Taylor L所说,你不能只是“停止”一个线程(通过调用一个简单的方法),因为它可能使你的系统处于不稳定状态,因为外部调用线程可能不知道是什么继续你的线程。
有了这样说,“停止”线程的最好方法是让线程密切关注自己并让它知道并理解何时应该停止。
答案 5 :(得分:0)
暂停线程和停止/删除线程之间存在差异。如果你停止意味着杀死线程,那么重启只是意味着创建一个新线程并启动。
有一些方法可以从不同的线程(例如,你的spawner)中杀死线程,但它们通常是不安全的。如果你的线程经常检查一些标志以确定它是否应该继续(我假设你的线程中有一些循环),并让外部“控制器”改变该标志的状态,那么它可能更安全。
你可以看到更多: http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
我可以问你为什么要杀死线程并重新启动它?为什么不等到它再次需要服务呢? Java具有完全用于此目的的同步机制。线程将处于休眠状态,直到控制器通知它继续执行。
答案 6 :(得分:0)
如果您的任务在循环中执行某种操作,则有一种方法可以暂停/重新启动处理,但我认为它必须超出Thread API当前提供的范围。如果是单次进程,我不知道有什么方法可以暂停/重新启动而不会遇到已被弃用或不再允许的API。
对于循环进程,我能想到的最简单的方法是生成Task的代码实例化ReentrantLock并将其传递给任务,并保留引用本身。每次任务进入其循环时,它都会尝试锁定ReentrantLock实例,当循环完成时,它应该解锁。您可能希望封装所有这些try / finally,确保在循环结束时放开锁定,即使抛出异常也是如此。
如果你想暂停任务,只需尝试从主代码锁定(因为你保持参考方便)。这将做的是等待循环完成,不要让它开始另一次迭代(因为主线程持有一个锁)。要重新启动线程,只需从主代码解锁,这将允许任务恢复其循环。
要永久停止线程,我会使用普通的API,或者在Task中留一个标志,并为标志设置一个setter(类似于stopImmediately)。当循环遇到该标志的真值时,它将停止处理并完成运行方法。
答案 7 :(得分:0)
DrawableCompat.setTint(imageView.getDrawable(), ContextCompat.getColor(v.getContext(), R.color.iconGray));
建议创建一个新线程而不是重新启动它。
答案 8 :(得分:-1)
我完全不同意“你不能'阻止'一个主题”的说法。 对于一个棘手的问题,这是一个短视的观点。为什么呢?
定期检查中断标志实际上只是另一种形式的忙碌等待“何时检查标志和多久”的困难决定。可能非常难看或无法回答。 类线程也有方法“停止(Throwable throwable)”,不幸的是我不赞成这种方法。 在try-catch-finally语句中给出run()方法的主体: 为什么从外部调用stop(new MyRuntimeException())时,任何语句(来自正文内部)都可能抛出任何已检查或未经检查的异常?从外面真的出乎意料吗?然后重新抛出一些很少被捕获的意外RuntimeExceptions,因为它们通常是未知的?最后,catch-clauses必须处理异常 - 无论是来自内部还是外部。最后一块可以收拾整齐。 我希望,人们再次考虑这个设计问题。
我认为线程应该能够(通过自行终止)或被杀死(立即以异常终止)。
答案 9 :(得分:-1)
有时候如果启动Thread
并且它加载了一个下行动态类,它正在处理大量Thread
/ currentThread
睡眠而忽略中断的Exception
捕获,一个中断可能不足以完全退出执行。
在这种情况下,我们可以提供这些基于循环的中断:
while(th.isAlive()){
log.trace("Still processing Internally; Sending Interrupt;");
th.interrupt();
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}