如何在java中以快速干净的方式中止线程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/94011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:13:42  来源:igfitidea点击:

How to abort a thread in a fast and clean way in java?

javamultithreading

提问by jumar

Here is my problem: I've got a dialog with some parameters that the user can change (via a spinner for example). Each time one of these parameters is changed, I launch a thread to update a 3D view according to the new parameter value. If the user changes another value (or the same value again by clicking many times on the spinner arrow) while the first thread is working, I would like to abort the first thread (and the update of the 3D view) and launch a new one with the latest parameter value.

这是我的问题:我有一个对话框,其中包含一些用户可以更改的参数(例如,通过微调器)。每次更改这些参数之一时,我都会启动一个线程以根据新的参数值更新 3D 视图。如果用户在第一个线程工作时更改另一个值(或通过多次单击微调箭头再次更改相同的值),我想中止第一个线程(以及 3D 视图的更新)并启动一个新的与最新的参数值。

How can I do something like that?

我怎么能做这样的事情?

PS: There is no loop in the run()method of my thread, so checking for a flag is not an option: the thread updating the 3D view basically only calls a single method that is very long to execute. I can't add any flag in this method asking to abort either as I do not have access to its code.

PS:run()我的线程的方法中没有循环,因此检查标志不是一种选择:更新3D视图的线程基本上只调用一个执行时间很长的方法。我无法在此方法中添加任何要求中止的标志,因为我无权访问其代码。

采纳答案by skiphoppy

Try interrupt() as some have said to see if it makes any difference to your thread. If not, try destroying or closing a resource that will make the thread stop. That has a chance of being a little better than trying to throw Thread.stop() at it.

像有些人所说的那样尝试中断(),看看它是否对您的线程有任何影响。如果没有,请尝试销毁或关闭将使线程停止的资源。这有可能比尝试向其抛出 Thread.stop() 好一点。

If performance is tolerable, you might view each 3D update as a discrete non-interruptible event and just let it run through to conclusion, checking afterward if there's a new latest update to perform. This might make the GUI a little choppy to users, as they would be able to make five changes, then see the graphical results from how things were five changes ago, then see the result of their latest change. But depending on how long this process is, it might be tolerable, and it would avoid having to kill the thread. Design might look like this:

如果性能可以接受,您可以将每个 3D 更新视为一个离散的不可中断事件,然后让它运行到结论,然后检查是否有新的最新更新要执行。这可能会使 GUI 对用户来说有点不稳定,因为他们可以进行五次更改,然后查看五次更改前的图形结果,然后查看他们最新更改的结果。但是取决于这个过程有多长,它可能是可以容忍的,并且可以避免不得不杀死线程。设计可能如下所示:

boolean stopFlag = false;
Object[] latestArgs = null;

public void run() {
  while (!stopFlag) {
    if (latestArgs != null) {
      Object[] args = latestArgs;
      latestArgs = null;
      perform3dUpdate(args);
    } else {
      Thread.sleep(500);
    }
  }
}

public void endThread() {
  stopFlag = true;
}

public void updateSettings(Object[] args) {
  latestArgs = args;
}

回答by Dave L.

The thread that is updating the 3D view should periodically check some flag (use a volatile boolean) to see if it should terminate. When you want to abort the thread, just set the flag. When the thread next checks the flag, it should simply break out of whatever loop it is using to update the view and return from its runmethod.

更新 3D 视图的线程应该定期检查某个标志(使用 a volatile boolean)以查看它是否应该终止。当您想中止线程时,只需设置标志即可。当线程接下来检查标志时,它应该简单地跳出它用来更新视图并从其run方法返回的任何循环。

If you truly cannot access the code the Thread is running to have it check a flag, then there is no safe way to stop the Thread. Does this Thread ever terminate normally before your application completes? If so, what causes it to stop?

如果您确实无法访问线程正在运行的代码来检查标志,则没有安全的方法来停止线程。在您的应用程序完成之前,此线程是否会正常终止?如果是这样,是什么导致它停止?

If it runs for some long period of time, and you simply must end it, you can consider using the deprecated Thread.stop()method. However, it was deprecated for a good reason. If that Thread is stopped while in the middle of some operation that leaves something in an inconsistent state or some resource not cleaned up properly, then you could be in trouble. Here's a note from the documentation:

如果它运行了很长一段时间,而您只是必须结束它,则可以考虑使用已弃用的Thread.stop()方法。然而,它被弃用是有充分理由的。如果该线程在某些操作中间停止,导致某些内容处于不一致状态或某些资源未正确清理,那么您可能会遇到麻烦。这是文档中的注释:

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait. For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?

这种方法本质上是不安全的。使用 Thread.stop 停止线程会使其解锁所有已锁定的监视器(这是未经检查的 ThreadDeath 异常向上传播堆栈的自然结果)。如果先前受这些监视器保护的任何对象处于不一致状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。stop 的许多用途应该被替换为简单地修改一些变量以指示目标线程应该停止运行的代码。目标线程应该定期检查这个变量,如果变量表明它要停止运行,则以有序的方式从它的 run 方法返回。如果目标线程等待很长时间(例如,在条件变量上),应该使用interrupt方法来中断等待。有关更多信息,请参阅为什么不推荐使用 Thread.stop、Thread.suspend 和 Thread.resume?

回答by Olvagor

Maybe this can help you: How can we kill a running thread in Java?

也许这可以帮助您:我们如何在 Java 中杀死正在运行的线程?

You can kill a particular thread by setting an external class variable.

您可以通过设置外部类变量来终止特定线程。

 Class Outer
 {    
    public static flag=true;
    Outer()
    {
        new Test().start();
    } 
    class Test extends Thread
    {               
       public void run()
       {
         while(Outer.flag)
         {
          //do your work here
         }  
       }
    }
  } 

if you want to stop the above thread, set flag variable to false. The other way to kill a thread is just registering it in ThreadGroup, then call destroy(). This way can also be used to kill similar threads by creating them as group or register with group.

如果要停止上述线程,请将标志变量设置为false. 另一种杀死线程的方法是在 ThreadGroup 中注册它,然后调用destroy(). 这种方式也可以用于通过将它们创建为组或向组注册来杀死相似的线程。

回答by freespace

The way I have implemented something like this in the past is to implement a shutdown()method in my Runnablesubclass which sets an instance variable called should_shutdownto true. The run()method normally does something in a loop, and will periodically check should_shutdownand when it is true, returns, or calls do_shutdown()and then returns.

我过去实现这样的shutdown()方法的方法是在我的Runnable子类中实现一个方法,该方法将一个实例变量设置should_shutdown为 true。该run()方法通常在循环中执行某些操作,并且会定期检查should_shutdown并在它为真时返回,或调用do_shutdown()然后返回。

You should keep a reference to the current worker thread handy, and when the user changes a value, call shutdown()on the current thread, and wait for it to shutdown. Then you can launch a new thread.

你应该保持对当前工作线程的引用,当用户改变一个值时,调用shutdown()当前线程,并等待它关闭。然后你可以启动一个新线程。

I would not recommend using Thread.stopas it was deprecated last time I checked.

我不建议使用,Thread.stop因为上次检查时它已被弃用。

Edit:

编辑:

Read your comment about how your worker thread just calls another method which takes a while to run, so the above does not apply. In this case, your only real options are to try calling interrupt()and see if has any effect. If not, consider somehow manually causing the function your worker thread is calling to break. For example, it sounds like it is doing some complex rendering, so maybe destroy the canvas and cause it to throw an exception. This is not a nice solution, but as far as I can tell, this is the only way to stop a thread in suituations like this.

阅读有关您的工作线程如何仅调用另一个需要一段时间才能运行的方法的评论,因此上述内容不适用。在这种情况下,您唯一真正的选择是尝试调用interrupt()并查看是否有任何效果。如果没有,请考虑以某种方式手动导致您的工作线程正在调用的函数中断。例如,听起来它正在做一些复杂的渲染,所以可能会破坏画布并导致它抛出异常。这不是一个很好的解决方案,但据我所知,这是在这种情况下停止线程的唯一方法。

回答by Rich Adams

A thread will exit once it's run()method is complete, so you need some check which will make it finish the method.

线程将在其run()方法完成后退出,因此您需要进行一些检查以使其完成该方法。

You can interrupt the thread, and then have some check which would periodically check isInterrupted()and return out of the run()method.

您可以中断线程,然后进行一些检查,这些检查会定期检查isInterrupted()并从run()方法中返回。

You could also use a boolean which gets periodically checked within the thread, and makes it return if so, or put the thread inside a loop if it's doing some repetative task and it will then exit the run() method when you set the boolean. For example,

您还可以使用在线程内定期检查的布尔值,如果是,则使其返回,或者如果线程正在执行某些重复任务,则将线程放入循环中,然后在设置布尔值时退出 run() 方法。例如,

static boolean shouldExit = false;
Thread t = new Thread(new Runnable() {
    public void run() {
        while (!shouldExit) {
            // do stuff
        }
    }
}).start();

回答by bmeck

Unfortunately killing a thread is inherently unsafe due to the possibilities of using resources that can be synchronized by locks and if the thread you kill currently has a lock could result in the program going into deadlock (constant attempt to grab a resource that cannot be obtained). You will have to manually check if it needs to be killed from the thread that you want to stop. Volatile will ensure checking the variable's true value rather than something that may have been stored previously. On a side note Thread.join on the exiting thread to ensure you wait until the dying thread is actually gone before you do anything rather than checking all the time.

不幸的是,由于使用可以通过锁同步的资源的可能性,杀死线程本质上是不安全的,并且如果您杀死的线程当前具有锁,则可能导致程序陷入死锁(不断尝试获取无法获得的资源) . 您必须手动检查是否需要从要停止的线程中杀死它。Volatile 将确保检查变量的真实值,而不是之前可能已存储的值。附带说明 Thread.join 在退出线程上确保您等到死亡线程实际上消失后再做任何事情,而不是一直检查。

回答by basszero

Instead of rolling your own boolean flag, why not just use the thread interrupt mechanism already in Java threads? Depending on how the internals were implemented in the code you can't change, you may be able to abort part of its execution too.

与其滚动你自己的布尔标志,为什么不直接使用 Java 线程中已有的线程中断机制呢?根据您无法更改的代码中内部实现的方式,您也可以中止部分执行。

Outer Thread:

外螺纹:

if(oldThread.isRunning())
{
    oldThread.interrupt();
    // Be careful if you're doing this in response to a user
    // action on the Event Thread
    // Blocking the Event Dispatch Thread in Java is BAD BAD BAD
    oldThread.join();
}

oldThread = new Thread(someRunnable);
oldThread.start();

Inner Runnable/Thread:

内部可运行/线程:

public void run()
{
    // If this is all you're doing, interrupts and boolean flags may not work
    callExternalMethod(args);
}

public void run()
{
    while(!Thread.currentThread().isInterrupted)
    {
        // If you have multiple steps in here, check interrupted peridically and
        // abort the while loop cleanly
    }
}

回答by toluju

Since you're dealing with code you don't have access to you're probably out of luck. The standard procedure (as outlined in the other answers) is to have a flag that is checked periodically by the running thread. If the flag is set, do cleanup and exit.

由于您正在处理您无法访问的代码,因此您可能不走运。标准程序(如其他答案中所述)是有一个标志,由正在运行的线程定期检查。如果设置了标志,则执行清理并退出。

Since that option is not available to you, the only other option is to force quit the running process. This used to be possible by calling Thread.stop(), but that method has been permanently deprecated for the following reason (copied from the javadocs):

由于该选项对您不可用,唯一的其他选项是强制退出正在运行的进程。这曾经可以通过调用Thread.stop() 来实现,但由于以下原因(从 javadoc 复制,该方法已被永久弃用:

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior.

这种方法本质上是不安全的。使用 Thread.stop 停止线程会使其解锁所有已锁定的监视器(这是未经检查的 ThreadDeath 异常向上传播堆栈的自然结果)。如果之前受这些监视器保护的任何对象处于不一致状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。

More info on this topic can be found here.

可以在此处找到有关此主题的更多信息。

One absolute sure way you could accomplish your request (although this is not a very efficient way to do this) is to start a new java process via Runtime.exec()and then stopping that process as necessary via Process.destroy(). Sharing state between processes like this is not exactly trivial, however.

您可以完成请求的一种绝对可靠的方法(尽管这不是一种非常有效的方法)是通过Runtime.exec()启动一个新的 java 进程,然后根据需要通过Process.destroy()停止该进程。然而,像这样在进程之间共享状态并非微不足道。

回答by Nerdfest

Instead of playing with thread starting and stopping, have you considered having the thread observe the properties that you're changing through your interface? You will at some point still want a stop condition for your thread, but this can be done this was as well. If you're a fan of MVC, this fits nicely into that sort of design

您是否考虑过让线程观察您通过界面更改的属性,而不是玩线程启动和停止?在某些时候,您仍然需要线程的停止条件,但这也可以做到。如果你是 MVC 的粉丝,这很适合这种设计

Sorry, after re-reading your question, neither this nor any of the other 'check variable' suggestions will solve your problem.

抱歉,在重新阅读您的问题后,此建议或任何其他“检查变量”建议均无法解决您的问题。

回答by jsight

Isn't this a little like asking "How can I abort a thread when no method other than Thread.stop() is available?"

这不是有点像问“当除了 Thread.stop() 之外没有其他方法可用时,我如何中止线程?”

Obviously, the only valid answer is Thread.stop(). Its ugly, could break things in some circumstances, can lead to memory/resource leaks, and is frowned upon by TLEJD (The League of Extraordinary Java Developers), however it can still be useful in a few cases like this. There really isn't any other method if the third party code doesn't have some close method available to it.

显然,唯一有效的答案是 Thread.stop()。它丑陋,在某些情况下可能会破坏事物,可能导致内存/资源泄漏,并且被 TLEJD(杰出 Java 开发人员联盟)所反对,但它在某些情况下仍然有用。如果第三方代码没有可用的关闭方法,那么真的没有任何其他方法。

OTOH, sometimes there are backdoor close methods. Ie, closing an underlying stream that its working with, or some other resource that it needs to do its job. This is seldom better than just calling Thread.stop() and letting it experience a ThreadDeathException, however.

OTOH,有时有后门关闭方法。即,关闭与其一起工作的底层流,或它完成其工作所需的其他一些资源。然而,这很少比仅仅调用 Thread.stop() 并让它经历 ThreadDeathException 更好。

回答by Javamann

You appear to not have any control over the thread that is rendering the screen but you do appear to have control of the spinner component. I would disable the spinner while the thread is rendering the screen. This way the user at least has some feedback relating to their actions.

您似乎无法控制渲染屏幕的线程,但您似乎可以控制微调组件。我会在线程渲染屏幕时禁用微调器。这样用户至少有一些与他们的行为有关的反馈。