如何在Java中终止线程?

如何在Java中终止线程?,java,multithreading,Java,Multithreading,如何在java中杀死java.lang.Thread?请参见此。它详细介绍了为什么这是一个糟糕的方法,以及通常应该做些什么来安全地停止线程 他们推荐的方法是使用一个共享变量作为标志,要求后台线程停止。然后,可以通过请求线程终止的不同对象设置此变量 通常情况下,你不会 您要求它使用 一种方法是设置一个类变量并将其用作哨兵,这可以很好地解释为什么存在于javadoc中 Class Outer { public static volatile flag = true; Outer()

如何在java中杀死java.lang.Thread?

请参见此。它详细介绍了为什么这是一个糟糕的方法,以及通常应该做些什么来安全地停止线程

他们推荐的方法是使用一个共享变量作为标志,要求后台线程停止。然后,可以通过请求线程终止的不同对象设置此变量

通常情况下,你不会

您要求它使用


一种方法是设置一个类变量并将其用作哨兵,这可以很好地解释为什么存在于javadoc中

Class Outer {
    public static volatile flag = true;

    Outer() {
        new Test().start();
    }
    class Test extends Thread {

        public void run() {
            while (Outer.flag) {
                //do stuff here
            }
        }
    }

}

设置外部类变量,即上例中的flag=true。将其设置为false以“杀死”线程。

当然,在这种情况下,您正在运行某种不完全可信的代码。我个人通过允许上传的脚本在我的Java环境中执行实现了这一点。是的,到处都有安全警报响起,但这是应用程序的一部分。在这个不幸的例子中,您首先只是希望脚本编写者尊重某种布尔的run/not-run信号。如果线程的运行时间超过某个超时时间,那么您唯一体面的故障保护就是调用该线程上的stop方法


但是,这是很好的,不是绝对的,因为代码可以捕获ThreadDeath错误或您显式抛出的任何异常,而不是像绅士线程应该做的那样重新触发它。因此,底线是AFAIA没有绝对的故障保护

在Java中,线程不会被终止,但线程的停止是以协作方式完成的。线程被要求终止,然后线程可以正常关闭

通常使用易失性布尔字段,线程会定期检查该字段,并在设置为相应值时终止

我不会使用布尔值来检查线程是否应该终止。如果您使用volatile作为字段修饰符,这将是可靠的,但是如果您的代码变得更加复杂,因为在while循环中使用了其他阻塞方法,那么您的代码可能根本不会终止,或者至少需要更长的时间

某些阻塞库方法支持中断

每个线程都有一个布尔标志interrupted status,您应该使用它。它可以这样实现:

public void run() {
   try {
      while (!interrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }
}

public void cancel() { interrupt(); }

源代码改编自。由于cancel方法是公共的,您可以让另一个线程根据需要调用此方法。

这个问题相当模糊。如果您的意思是“如何编写程序,使线程在需要时停止运行”,那么其他各种响应应该会有所帮助。但如果你的意思是“我有一个服务器出现紧急情况,我现在无法重新启动,我只需要一个特定的线程就可以了,不管发生什么”,那么你需要一个干预工具来匹配像jstack这样的监控工具


为了这个目的,我创造了。请参阅其使用说明。

有一种方法可以做到这一点。但是如果你不得不使用它,要么你是一个糟糕的程序员,要么你使用的是一个糟糕的程序员编写的代码。所以,你应该考虑停止做一个糟糕的程序员或者停止使用这种糟糕的代码。 此解决方案仅适用于没有其他方法的情况

Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );

没有办法优雅地终止线程

您可以尝试中断线程,一种常见的策略是使用毒丸来通知线程停止自身

public class CancelSupport {
    public static class CommandExecutor implements Runnable {
            private BlockingQueue<String> queue;
            public static final String POISON_PILL  = “stopnow”;
            public CommandExecutor(BlockingQueue<String> queue) {
                    this.queue=queue;
            }
            @Override
            public void run() {
                    boolean stop=false;
                    while(!stop) {
                            try {
                                    String command=queue.take();
                                    if(POISON_PILL.equals(command)) {
                                            stop=true;
                                    } else {
                                            // do command
                                            System.out.println(command);
                                    }
                            } catch (InterruptedException e) {
                                    stop=true;
                            }
                    }
                    System.out.println(“Stopping execution”);
            }

    }
}


线程突然终止的尝试是众所周知的糟糕编程实践,也是应用程序设计不佳的证据。多线程应用程序中的所有线程显式和隐式共享相同的进程状态,并强制彼此协作以保持一致,否则应用程序将容易出现错误,这将很难诊断。因此,开发人员有责任通过仔细和清晰的应用程序设计来保证这种一致性

对于受控线程终端,有两种主要的正确解决方案:

共享易失性标志的使用 使用一对Thread.interrupt和Thread.interrupted方法。 有关线程突然终止相关问题的详细说明以及受控线程终止的错误和正确解决方案示例,请参见:


我想根据积累的评论补充几点意见

如果安全管理器允许,Thread.stop将停止线程。 停止是危险的。话虽如此,如果您在JEE环境中工作,并且无法控制所调用的代码,那么这可能是必要的;看见 永远不要停止容器工作线程。如果您想运行易于挂起的代码,请小心地启动一个新的守护进程线程并对其进行监视,必要时终止。 stop在调用线程上创建一个新的ThreadDeatherError错误,然后在目标线程上抛出该错误。因此, 堆栈跟踪通常毫无价值。 在JRE 6中,停止与安全管理器的检查,然后调用调用stop1的stop0。stop0是本机代码。 截至Java 13,Thread.stop尚未删除,但Thread.stopThrowable已在Java 11中删除, 我会投线程的票。停

例如,您有一个持久的操作,如网络请求。 假设您正在等待响应,但这可能需要时间,用户会导航到其他UI。 这个等待线程现在是一个无用的b潜在问题,因为当他得到结果时,它是完全无用的,他将触发回调,从而导致大量错误

所有这些,他都可以进行CPU密集的响应处理。作为一名开发人员,您甚至无法阻止它,因为如果Thread.currentThread.isInterrupted在所有代码中都有行,则无法抛出


因此,无法强制阻止线程是很奇怪的。

以下是一些关于这个主题的好文章:


我没有让中断在Android中工作,所以我使用了这种方法,工作非常完美:

boolean shouldCheckUpdates = true;

private void startupCheckForUpdatesEveryFewSeconds() {
    Thread t = new Thread(new CheckUpdates());
    t.start();
}

private class CheckUpdates implements Runnable{
    public void run() {
        while (shouldCheckUpdates){
            //Thread sleep 3 seconds
            System.out.println("Do your thing here");
        }
    }
}

 public void stop(){
        shouldCheckUpdates = false;
 }

一般来说,您不会终止、停止或中断线程,也不会检查线程是否被中断,而是让它自然终止

这很简单。您可以在run方法中使用任意循环和volatile boolean变量来控制线程的活动。您还可以从活动线程返回到主线程以停止它


通过这种方式,您可以优雅地终止线程:。

“终止线程”不是正确的短语。下面是一种方法,我们可以随意实现线程的优雅完成/退出:

我使用的Runnable:

class TaskThread implements Runnable {

    boolean shouldStop;

    public TaskThread(boolean shouldStop) {
        this.shouldStop = shouldStop;
    }

    @Override
    public void run() {

        System.out.println("Thread has started");

        while (!shouldStop) {
            // do something
        }

        System.out.println("Thread has ended");

    }

    public void stop() {
        shouldStop = true;
    }

}
触发类:

public class ThreadStop {

    public static void main(String[] args) {

        System.out.println("Start");

        // Start the thread
        TaskThread task = new TaskThread(false);
        Thread t = new Thread(task);
        t.start();

        // Stop the thread
        task.stop();

        System.out.println("End");

    }

}

Thread.stop已弃用,那么如何在java中停止线程

始终使用中断方法和future来请求取消

例如,当任务响应中断信号时,阻塞队列采用方法。 当任务不响应中断信号时。假设任务执行不响应中断信号的套接字I/O,因此使用上述方法不会中止任务,future将超时,但cancel in finally块将不起作用,线程将继续侦听套接字。如果由池实现,我们可以在连接上关闭套接字或调用close方法。
如果您检查中断isAlive的线程,它将返回true,并且它们将继续添加到当前线程组[],您可以使用thread.currentThread.getThreadGroup.list看到这一点;它会打印所有线程,如果你重复你的流程,你会看到线程的多个实例。如果你在PC上,那么这没有问题,但是如果你正在为移动android开发一个软件,我已经体验过了,那么你会从内存错误中解脱出来。可以/应该注意,如建议中所述,为了确保通过标志进行停止请求的即时通信,变量必须是可变的,或者对变量的访问必须是同步的。此时该链接已被终止。不过,我可以在archive.org上找到它:我使用java.sql.DriverManager中的getConnection方法。如果连接attemt花费的时间太长,我会尝试通过调用thread.interrupt终止相应的线程,但它根本不会影响线程。然而,Thread.stop可以工作,尽管oracle说如果中断不能工作,它就不应该工作。我想知道如何使它工作,并避免使用不推荐的方法;因为destroy从来都不是因为死锁而实现的,所以我更喜欢关于这个问题的ExecutorStatus的答案:@loungerdork我认为Java应该为失控的线程实现一个安全的停止/销毁方法,尽管有丢失锁和其他陷阱的警告,所以你想要一个不安全的线程停止。我想你们已经有一个了。令人惊讶的是,什么样的问题会在2009年获得212张选票。这将在今天被立即销毁。@JonathonReinhart:为什么?这似乎是一个合法的问题,即使是现在。也许您不知道当您有失控的线程时,它会导致什么样的挫折感,并且只能使用不推荐的函数以某种方式处理这个问题?正如一个附带提示:只有当线程运行并且没有被卡住时,变量as flag才起作用。中断应该将线程从等待、睡眠、网络读取等大多数等待条件中释放出来。因此,你永远不应该捕捉到中断异常来实现这一点;使标志易变,以确保它在任何地方都能正常工作。内部类不是静态的,因此标志应该是一个实例变量。应该在访问器方法中清除该标志,以便可以执行中断等其他操作。name标志不是描述性的。我在run方法中没有while。这是否意味着在run方法中编写的任何内容都将被重复?这不是我们希望线程首先做的事情:+1正在做!首选Thread.currentThread.isInteruppted当您在内部打开外部进程时,两种情况都会失败
e当{//open ext process}并且该进程被挂起时,现在既不会中断线程,也不会到达末尾检查布尔条件,而您将被挂起。。。例如,使用java.exec启动一个python控制台,并尝试在不写exit的情况下获取控件,然后查看是否有方法终止该进程并退出。。。。无法摆脱这种情况……完全没有理由这样做,因为即使public Thread.stop已被弃用,仍然可以调用它。@Lii Thread.stop也会执行相同的操作,但还会检查访问和权限。使用Thread.stop是很明显的,我不记得为什么我使用Thread.stop0来代替它。可能Thread.stop不适用于我在Java6上的特例Weblogic。或者可能是因为Thread.stop已被弃用并导致警告。在我的场景中,这是停止无休止运行的线程的唯一方法。出于某些原因。stop没有停止线程,但是stop0没有停止。如果您以插件或脚本的形式运行不受信任的代码,该怎么办?Java为不受信任的代码嵌入了沙箱。而沙箱是无用的,它允许在没有强制停止的情况下工作。假设您正在java上编写浏览器。杀死任意页面脚本的能力是无价的。@ayvango然后你必须在自己的沙箱中运行该脚本。Java沙盒保护机器不受应用程序的影响,而不是应用程序的各个部分相互影响。@DavidSchwartz你的意思是,我应该使用其他平台,而不是Java?@ayvango你仍然可以使用Java沙盒保护机器不受应用程序的影响。但是,如果您想保护应用程序的某些部分不受应用程序其他部分的影响,那么您需要选择一些能够做到这一点的工具。我尝试过这样做,但相信cancel是从与run不同的线程调用的,而interrupt在可运行类Java 8上不可用。我最终将线程句柄存储到volatile thread runningThread,这要感谢volatile点,并在cancel中调用runningThread.interrupt。如果网络操作已经可以安全中止,只需中断线程即可。如果网络操作不可安全中止,则无法调用Thread.stop。您不是在投票支持Thread.stop,您是在要求每一个执行可能需要很长时间才能使其安全中止的操作的人。这可能是个好主意,但它与实现Thread.stop作为请求安全终止的方式无关。我们已经中断了。所以无法强制停止线程是很奇怪的。-。。。直到您深入了解Java设计人员所做的工作并得出结论,没有任何技术上可行的解决方案比不推荐stop更糟糕。@Fredrik调用中断方法时线程上下文会发生什么变化?主要问题与每个新线程相关。@ABcDexter关键是中断不会中断任何内容,它只是向线程中的代码或线程调用的代码发出信号,表示有人要求它中断正在执行的任何操作。然后线程应该很好地停止处理并返回,就像它做了应该做的事情一样,此时线程上下文可能也被丢弃。OTOH,如果你真的强制停止线程,你的问题会很好,答案也不会被定义。因为程序不再由单个开发人员编写,所以终止线程通常是必要的。因此,不能将其视为糟糕的编程。我无法想象没有kill的Linux。无法杀死线程是Java的缺陷。真棒,真命天子。。。如果您必须调用某个第三方库,您无法控制该库,该库存在错误超时,并且在执行时可能每1000-2000次挂起一次,该怎么办?糟糕的编程实践,嗯?你不能总是访问你正在使用的代码。无论如何,op是问如何杀死一个线程,而不是在设计自己的代码时如何控制它的流……问题是当你杀死一个拥有互斥锁或分配了一些内存块的线程,或者哪个线程应该生成其他线程正在等待的一些事件或数据时,会发生什么?应用程序的其余逻辑将发生什么变化?您将始终面临这样的风险,即小而明显的问题将转化为复杂的问题,这将很难重现和调查。终止线程是不安全的,因为它会使应用程序处于许多不同的不一致状态。看看cert.org上的链接上的信息。我们有一个控制线程,在某些情况下可能会决定整个计算变得毫无意义。做实际工作的许多不同的Runnable需要在任何方便的地方使用isInterrupted的一些变体进行飞溅-多么可怕!如果控制器让线程死机看起来不知从何而来,干净地释放所有同步的&最后是块,那就更好了。每个人都说这是错误的
一个,但对于完全不相关的线程,我不明白为什么要将.volatile关键字添加到shouldCheckUpdates中,以防编译器使用线程本地存储进行优化。AFAIK越来越多的服务正在变得混合,并使用托管环境来执行第三方代码插件、脚本等,它们无法完全控制代码,完全取消线程似乎不合理。停止讨论,因为对于服务工程师来说,活动和服务状态可能会比非服务状态好得多,因为挂起会带走线程,或者忙着无限循环会带走核心谢谢!正是我要找的!volatile关键字应添加到shouldStop变量中,以防编译器使用线程本地存储进行优化。如果//do something是一个需要很长时间才能完成的阻塞任务,则此操作不起作用。
public class ThreadStop {

    public static void main(String[] args) {

        System.out.println("Start");

        // Start the thread
        TaskThread task = new TaskThread(false);
        Thread t = new Thread(task);
        t.start();

        // Stop the thread
        task.stop();

        System.out.println("End");

    }

}
Callable < String > callable = new Callable < String > () {
    @Override
    public String call() throws Exception {
        String result = "";
        try {
            //assume below take method is blocked as no work is produced.
            result = queue.take();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return result;
    }
};
Future future = executor.submit(callable);
try {
    String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    logger.error("Thread timedout!");
    return "";
} finally {
    //this will call interrupt on queue which will abort the operation.
    //if it completes before time out, it has no side effects
    future.cancel(true);
}

public interface CustomCallable < T > extends Callable < T > {
    void cancel();
    RunnableFuture < T > newTask();
}

public class CustomExecutorPool extends ThreadPoolExecutor {
    protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
        if (callable instanceof CancellableTask)
            return ((CancellableTask < T > ) callable).newTask();
        else
            return super.newTaskFor(callable);
    }
}

public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
    public synchronized void cancel() {
        try {
            obj.close();
        } catch (IOException e) {
            logger.error("io exception", e);
        }
    }

    public RunnableFuture < T > newTask() {
        return new FutureTask < T > (this) {
            public boolean cancel(boolean mayInterruptIfRunning) {
                try {
                    this.cancel();
                } finally {
                    return super.cancel(mayInterruptIfRunning);
                }
            }

        };
    }
}