繁体   English   中英

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

[英]How to start/stop/restart a thread in Java?

我真的很难找到一种在 Java 中启动、停止和重新启动线程的方法。

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

我的第一次尝试是使用ExecutorService但我似乎找不到重新启动任务的方法。 当我使用.shutdownnow()以后对.shutdownnow()任何调用.execute()失败,因为ExecutorService是“关闭”...

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

一旦线程停止,您将无法重新启动它。 但是,没有什么可以阻止您创建和启动新线程。

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

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

根据评论编辑:

要“杀死”线程,您可以执行以下操作。

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

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

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

如果线程的内容不允许终止其执行,则您不能终止该线程。

在您的帖子中,您说:“我的第一次尝试是使用 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()”,但为什么这是个坏主意? 当您停止线程时,该线程可能位于代码的同步(或其他临界区,但我们将限制在由同步关键字保护的设置)部分。 同步块应该在它们的整体中执行,并且在被其他线程访问之前只能由一个线程执行。 如果您在同步块中间停止线程,则同步块设置的保护将失效,您的程序将进入未知状态。 开发人员将内容放入同步块中以保持同步,如果您使用 threadInstance.stop() 您破坏了同步的含义,该代码的开发人员试图完成的工作以及该代码的开发人员希望他的同步块如何表现。

查看java.lang.Thread

启动或重新启动(一旦一个线程停止,你就不能重新启动同一个线程,但这没有关系;只需创建一个新的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

您无法重新启动线程,因此最好的选择是在线程停止时保存对象的当前状态,当需要继续对该对象进行操作时,您可以使用保存的对象重新创建该对象,然后启动新线程.

Swing WorkerConcurrency这两篇文章可能会帮助您确定问题的最佳解决方案。

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

话虽如此,“停止”线程的最佳方法是让线程关注自身并让它知道并理解何时应该停止。

暂停线程和停止/杀死它是有区别的。 如果为您停止意味着杀死线程,那么重新启动仅意味着创建一个新线程并启动。

有一些方法可以杀死来自不同线程(例如,您的 spawner)的线程,但它们通常是不安全的。 如果您的线程不断检查某个标志以查看它是否应该继续(我假设您的线程中有一些循环),并让外部“控制器”更改该标志的状态,则可能会更安全。

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

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

如果您的任务在循环中执行某种操作,则有一种方法可以暂停/重新启动处理,但我认为它必须超出 Thread API 当前提供的范围。 如果是单次处理,我不知道有什么方法可以在不运行已弃用或不再允许的 API 的情况下暂停/重新启动。

对于循环进程,我能想到的最简单的方法是生成任务的代码实例化一个 ReentrantLock 并将其传递给任务,同时保持引用本身。 每次任务进入其循环时,它都会尝试锁定 ReentrantLock 实例,当循环完成时,它应该解锁。 您可能希望封装所有这些 try/finally,确保在循环结束时释放锁,即使抛出异常也是如此。

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

要永久停止线程,我将使用普通 API 或在任务中留下一个标志和一个标志的设置器(类似于 stopImmediately)。 当循环遇到此标志的真值时,它会停止处理并完成 run 方法。

我完全不同意“您不能'停止'线程”的说法。 对于棘手的问题,这是一种短视的观点。 为什么?

定期检查中断标志实际上只是忙于等待“何时检查标志以及多久检查一次”这一困难决定的另一种形式。 可能很难看或无法回答。 该类线程还具有“ stop(Throwable throwable)”方法,不幸的是我不赞成使用该方法。 给定方法run()及其主体在try-catch-finally语句中:为什么可以(在主体内部)任何语句都可以在调用stop(new MyRuntimeException())时抛出任何已检查或未检查的异常从外面可能不会? 从外面真的真的那么出人意料吗? 那么,如何抛出意外的RuntimeException异常,而这些异常却很少被捕获,因为它们通常是未知的,那又如何呢? 最后,抓住条款必须处理异常-无论是从内部还是从外部。 最后一块可以收拾起来。 希望人们再次考虑该设计问题。

我认为线程应该能够死(通过自行终止)或被杀死(立即终止,但有例外)。

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

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

while(th.isAlive()){
    log.trace("Still processing Internally; Sending Interrupt;");
    th.interrupt();
    try {
        Thread.currentThread().sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
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());

建议创建一个新线程而不是重新启动它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM