多线程-如何在Java中启动/停止/重新启动线程?
我很难找到一种方法来启动,停止和重新启动Java中的线程。
具体来说,我在文件.shutdownnow()中有一个类Task(当前实现ExecutorService)。我的主应用程序需要能够在线程上启动此任务,在需要时停止(杀死)该线程,有时杀死并重新启动该线程。 ...
我的第一次尝试是ExecutorService,但似乎无法找到重启任务的方法。 当我使用.shutdownnow()时,将来对.execute()的调用都会失败,因为ExecutorService是“关机” ...
那么,我该怎么做呢?
10个解决方案
42 votes
一旦线程停止,您将无法重新启动它。 但是,没有什么可以阻止您创建和启动新线程。
选项1:创建一个新线程,而不是尝试重新启动。
选项2:与其让线程停止,不如让它等待,然后当它收到通知时,可以允许它再次工作。 这样,线程永远不会停止,并且永远不需要重新启动。
根据评论进行编辑:
要“杀死”线程,您可以执行以下操作。
yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop
Taylor Leese answered 2020-02-10T03:42:40Z
9 votes
评论Thread。
要启动或重新启动(一旦线程停止,您就无法重新启动同一线程,但这无关紧要;只需创建一个新的Thread实例):
// Create your Runnable instance
Task task = new Task(...);
// Start a thread and run your Runnable
Thread t = new Thread(task);
要停止它,请在您的Thread实例上有一个方法,该方法设置一个标志来告知Runnable方法退出;否则,请执行以下操作。 从Runnable返回的退出线程。 如果您的调用代码需要知道线程在返回之前确实已停止,则可以使用run:
// Tell Task to stop
task.setStopFlag(true);
// Wait for it to do so
t.join();
关于重新启动:即使Thread无法重新启动,您也可以在具有状态且希望保留的状态下用新线程重用Runnable实例。 这是同一件事。 只要确保您的Runnable设计为允许多次呼叫run。
T.J. Crowder answered 2020-02-10T03:43:14Z
9 votes
除非在该线程中运行的代码进行检查并允许终止,否则无法终止线程。
您说:“遗憾的是,我必须杀死/重新启动它……我无法完全控制线程的内容,而就我的情况而言,它需要重新启动”
如果线程的内容不允许终止执行,则无法终止线程。
在您的帖子中,您说:“我的初次尝试是使用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();
由于此线程检查是否已被中断/关闭/终止。
因此,如果您希望可以关闭一个线程,则需要确保它检查是否已被中断。 如果您想要一个可以“关闭”并“重新启动”的线程,则可以使该线程成为可运行的,可以执行前面提到的新任务。
为什么不能关闭正在运行的线程? 好吧,我实际上撒了谎,您可以调用“ yourThread.stop()”,但是为什么这是个坏主意呢? 当您停止线程时,该线程可能位于代码的同步(或其他关键部分,但我们将自己限制在此处受同步关键字保护的部分)中。 同步块应该完整地执行,并且只能由一个线程执行,然后才能被其他线程访问。 如果在synch块的中间停止线程,则synch块所设置的保护将失效,并且程序将进入未知状态。 开发人员将内容放置在同步块中以保持同步,如果您使用threadInstance.stop(),则会破坏同步的含义,该代码的开发人员试图完成的工作以及该代码的开发人员如何期望其同步块 表现。
Matt Crinklaw-Vogt answered 2020-02-10T03:44:17Z
5 votes
您无法重新启动线程,所以最好的选择是在线程停止时保存对象的当前状态,并且当需要继续对该对象进行操作时,可以使用保存的对象重新创建该对象,然后启动新线程 。
《 Swing Worker和并发性》这两篇文章可能会帮助您确定问题的最佳解决方案。
ChadNC answered 2020-02-10T03:44:42Z
3 votes
如Taylor L所述,由于外部调用线程可能不知道内部发生了什么,因此它不能使系统处于不稳定状态,因此不能仅仅“停止”线程(通过调用简单方法) 你的线程。
如此说来,“停止”线程的最佳方法是让线程注意自身并让其知道并了解何时停止。
JasCav answered 2020-02-10T03:45:06Z
1 votes
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());
建议创建一个新线程而不是重新启动它。
Sukirti Dash answered 2020-02-10T03:45:26Z
0 votes
如果您的任务正在循环中执行某种动作,则可以使用一种方法来暂停/重新启动处理,但是我认为它必须超出Thread API当前提供的范围。 如果是一个单一过程,那么我不知道有什么方法可以挂起/重新启动,而无需运行已弃用或不再允许使用的API。
对于循环过程,我想到的最简单的方法是,生成Task的代码实例化一个ReentrantLock并将其传递给任务,以及保留引用本身。 每当Task进入其循环时,它都会尝试对ReentrantLock实例进行锁定,并且在循环完成时应将其解锁。 您可能希望封装所有这些try / finally,确保即使在抛出异常的情况下,也可以在循环结束时放开锁。
如果要暂停任务,只需尝试锁定主代码即可(因为您已方便使用了参考)。 这样做是等待循环完成,而不是让它开始另一个迭代(因为主线程持有锁)。 要重新启动线程,只需从主代码解锁即可,这将使任务恢复其循环。
要永久停止线程,我将使用常规API或在Task中保留一个标志,并为该标志保留一个setter(类似于stopImmediately)。 当循环遇到该标志的真值时,它将停止处理并完成run方法。
Gennadiy answered 2020-02-10T03:46:01Z
0 votes
我完全不同意“您不能'停止'线程”的说法。这是一个棘手问题的短视观点。 为什么?
定期检查中断标志实际上只是忙于等待“何时检查标志以及多久检查一次”这一困难决定的另一种形式。 可能很难看或无法回答。该类线程还具有“ stop(Throwable throwable)”方法,不幸的是我不赞成使用该方法。给定方法run()及其主体在try-catch-finally语句中:为什么可以确定(从主体内部)任何语句都可以引发任何已检查或未检查的异常,而不能从外部调用stop(new MyRuntimeException())呢? 从外面真的真的那么出人意料吗? 那么,如何重新抛出意外的RuntimeException呢?由于它们通常是未知的,因此很少捕获? 最后,抓住条款必须处理异常-无论是从内部还是从外部。 最后一块可以收拾起来。希望人们再次考虑该设计问题。
我认为线程应该能够死(通过自行终止)或被杀死(立即终止,但有例外)。
mmirwaldt answered 2020-02-10T03:46:32Z
0 votes
有时,如果启动了Thread,并加载了下行动态类,该类正在处理大量Thread/currentThread睡眠,而忽略了已中断的Exception catch,则一个中断可能不足以完全退出执行。
在这种情况下,我们可以提供以下基于循环的中断:
while(th.isAlive()){
log.trace("Still processing Internally; Sending Interrupt;");
th.interrupt();
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Saravanan Thangavel answered 2020-02-10T03:46:57Z
0 votes
暂停线程与停止/杀死线程之间是有区别的。 如果停止为您意味着杀死线程,那么重新启动只是意味着创建一个新线程并启动。
有一些方法可以杀死其他线程(例如您的生成器)中的线程,但是通常这是不安全的。 如果您的线程不断检查某个标志以查看是否应该继续(我假设您的线程中存在一些循环),并让外部“控制器”更改该标志的状态,则可能会更安全。
您可以在以下位置看到更多信息:[http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html]
请问您为什么要终止线程并重新启动它? 为什么不让它等到再次需要它的服务呢? Java具有恰好为此目的的同步机制。 线程将一直处于休眠状态,直到控制器通知它继续执行。
Uri answered 2020-02-10T03:47:31Z