当前位置: 首页 > 知识库问答 >
问题:

为什么线程中断后不调用方法?

尹兴生
2023-03-14

我想优雅地关闭一个线程。然而,一旦关闭被启动,线程应该在结束通常的操作后执行一些关闭操作。

两个线程都使用Hibernate和/或等待,并处理中断异常,它们还在一个循环中处理任务,只需要几毫秒。所以我期望while循环结束,因为Thread.currentThread()。isInterrupted()变为“true”。

问题是,对于我的代码,有时我会得到日志“SHUTDOWN”,有时不会。此外,我只有有时会得到“InterRUPTED”,我当然理解。对于另一个类似的线程,我从来没有得到过“SHUTDOWN”。

ExecutorService executor = Executors.newFixedThreadPool(2);

executor.execute(new Test());

Thread.sleep(10000);

executor.shutdown();
        
try {
    if(this.executor.awaitTermination(60, TimeUnit.SECONDS)) {
        this.loggerFactory.getLogger(this.getClass()).info("CLOSED (GRACEFULLY)!");
    }  else {
        this.executor.shutdownNow();
        
        this.loggerFactory.getLogger(this.getClass()).info("CLOSED (IMMEDIATELY)!");
    }
} catch(InterruptedException e) {
    this.executor.shutdownNow();
            
    this.loggerFactory.getLogger(this.getClass()).info("CLOSED (IMMEDIATELY)!");
}
class Test implements Runnable {

    private volatile boolean isRunning = true;

    @Override
    public void run() {
        try {
            while(!Thread.currentThread().isInterrupted()) {
                while(!this.isRunning) {
                    synchronized(this) {
                        this.wait();
                    }
                }
                
                // DO SOMETHING LASTING A FEW MILLISECONDS
                    
                Thread.sleep(500);
            }
        } catch(InterruptedException e) {
            this.loggerFactory.getLogger(this.getClass()).info("INTERRUPTED!");
        }
        
        this.loggerFactory.getLogger(this.getClass()).info("SHUTDOWN!");

        // DO SOME SHUTDOWN OPERATION
    }

}

共有1个答案

仰成天
2023-03-14

编辑:

经过OP的一些评论,似乎有一个完全不同的,更优越的解决方案:

Java有一个“安装”关机挂钩的系统。当VM关闭时,有时会调用这些。如果您遇到SIGTERMed(kill-9),或者有人绊倒了电源线,或者linux由于内存使用过多而终止了您的进程,或者内核转储,或者VM硬崩溃(例如,本机代码中的核心转储),或者设备断电,那么当然不会调用它们。

但是,如果流程中有人运行<code>System。exit(),或者所有非守护进程线程都已完成,或者有人点击CTRL C或向您的进程发送SIGKILL(kill,而不是kill-9),它们将首先运行,只有当它们全部完成时,java进程才真正结束。

这听起来是一个非常好的解决方案。您的关机挂钩应该:

  1. 获取一些私人原子布尔值的锁。
  2. 将布尔值设置为 false(布尔值指示:我可以查询此传感器吗?
  3. 松开锁。
  4. 重置传感器。
  5. 返回。

读取该传感器的所有正常操作代码都应:

  1. 获取布尔值的锁。
  2. 如果为假,则抛出或以其他方式中止。
  3. 执行传感器读取操作。
  4. 释放锁。

没有锁,任何东西都不应该触碰传感器(如果不这样做,可能意味着你已经重置了传感器,可能会弄乱传感器,这将是糟糕的)。

原答案:

我想优雅地关闭一个线程。

为什么?“优雅地”是一个听起来很好的词,但一旦你深入了解它的意思,它只是令人讨厌的东西。这个词的意思是:“如果有人被电源线绊倒或我的应用程序硬崩溃,这将导致我的软件失败,可能会持续下去(如,如果不清理东西,就不会再启动)”。

更好的设计是有一个不需要关闭的线程。只需拔掉插头,一切都很好。

例如,旧的文件系统(MS-DOS和早期的windows系统)需要正常关闭;如果不这样做,就会导致持续的问题&系统根本无法启动,你把盒子塞住了。然后他们有了缓解系统(chkdsk系统),但现代操作系统要好得多。他们的文件系统处理设置基本上不在乎被“优雅地”关闭。只要拔掉插头,他们就会没事的,这就是期刊的作用。

所以我希望while循环结束,因为Thread.currentThread()。isInterrupted()变为“true”。

你不应该这样使用API。

以下是中断API的基本要点:

>

  • 任何线程都可以在其他线程上“提升中断标志”(someThread.interupt())。

    除非一个方法明确地决定查看它,否则除了提升标志之外,提升标志不会做任何其他事情。

    方法Thread.interrupted()是您应该如何读出标志以便对其采取行动的方式,__and不是Thread.currentThread(). isInter的()。前者将检查标志并清除它。后者仅检查标志。

    一些java方法被指定为响应标志的启动。您可以识别这些方法,因为它们<code>抛出InterruptedException</code>。可能有更多的方法;例如,在大多数操作系统上,中断当前正在等待更多字节从网络流入的线程(它们在从<code>套接字获取的<code>InputStream</code>上的<code>read()</code>调用中被阻塞)。getInputStream())将导致读取调用失败(使用IOException,而不是InterruptedException),因为read()未指定抛出Interrupted Ex),但这并不能保证;在某些操作系统上,它不会,你不能打断它。

    一般的策略是,在您处理中断标志的那一刻,您降低标志,而java代码就是这样做的:如果一个方法抛出InterroutedEx,该标志将被清除。

    Java没有定义中断时应该做什么。线程不会神奇地中断;例如,当VM关闭时(有人点击CTRL C),这不会中断任何线程。Java只会在所有线程上“拔掉插头”。这是因为这样更好(见上文)。因此,如果线程被中断,那是因为您编写了<code>线程。interrupt()某处,因此,您可以决定它的含义。也许这意味着“重新读取配置文件并重新启动服务器侦听进程”。也许这意味着“停止计算国际象棋的移动,并执行迄今为止发现的最佳移动”。也许它的意思是“重新检查病情”。也许它的意思是“完全结束线程”。这取决于你。没有标准。

    请注意,指定响应中断标志的各种方法(如< code>wait():它抛出InterruptedException)都有这个属性:如果在标志打开时调用它们,它们将通过抛出< code > interrupted exception 立即返回,它们甚至不会开始等待。

    因此,对于您的代码,假设您已经等待()了,只需使while(true)并依赖InterruptedEx。

  •  类似资料:
    • 在多线程程序中,我怀疑当一个线程等待()时,它不会占用太多的cpu利用率,以便cpu可以交换以处理其他线程。 例如,100个线程一起启动同一个任务,而50个线程实际执行该任务,而其他50个线程等待所有50个任务完成。后一种情况比前者花费的时间少得多。

    • 问题内容: 最近,我正在用Java开发多线程。想了解一个线程是否处于阻塞状态为什么不能被中断?为何只有在等待状态下才能中断线程?基本上,为什么我们需要两个可以被中断而另一个不能被中断的线程状态? 这个问题可能是非常基本的,但是,我试图理解事物,而不仅仅是记住它们。 问题答案: 有人认为您的意思是导致线程停止其当前操作并抛出?Java中的线程中断只是一个标志。您可以在BLOCKED线程上调用就好了,

    • 我对学习java中的方法还不熟悉。在python中,使用“函数”很容易,但我最近了解到java没有类似的功能。我有一个方法,应该返回n1和n2中的最低值。我在公共静态int函数的行中得到一个错误。。。 但语法似乎没有任何问题。

    • 看看下面例子中泛型类型的类型推断,我说不出为什么工作得很好,但是(几乎相同)无法编译,为了管理它,编译器需要额外的技巧,比如或。 导致编译器不确定表达式类型和方法结果类型是否兼容的问题是什么?

    • 问题内容: 我正在尝试制作我的第一个Android应用程序。我注意到,如果数据库不存在,则不会调用该方法来创建表。但是,即使我尝试调试,该方法也无法正常工作。 请查看下面的代码,并给我任何建议。任何帮助将不胜感激。 问题答案: 我也遇到了 SQLiteOpenHelper的 麻烦。对我有用的是存储成员变量 在SQLiteOpenHelper子类中并调用 在构造函数中。 该问题的答案还包括一些有用的

    • 问题内容: 我需要制作一个具有同步和异步功能的库。 -等到得到结果,然后返回结果。 -立即返回Future,如果需要,可以在完成其他操作后进行处理。 我图书馆的核心逻辑 客户将使用我们的库,他们将通过传递构建器对象来调用它。然后,我们将使用该对象构造一个URL,并通过执行该对象来对该URL进行HTTP客户端调用,并在将响应作为JSON字符串返回给我们之后,通过创建对象将该JSON字符串发送回给我们