【问题标题】:Might a finally block not get executed when a thread is interrupted/killed?当线程被中断/杀死时,finally 块可能不会被执行吗?
【发布时间】:2013-10-21 17:32:36
【问题描述】:

the Java tutorial 中提到了try { ... } finally { ... }

注意:如果在执行 try 或 catch 代码时 JVM 退出, 那么finally块可能不会执行。同样,如果 线程 执行 try 或 catch 代码被中断或杀死,finally 即使应用程序作为一个整体,块也可能不会执行 继续

线程是否可以被interrupted杀死 (I thought that was impossible?)这样finally块在JVM运行时不会被执行此线程退出/终止? (我很困惑,因为上面的引用非常明确,没有太多误解的余地。)

编辑:将问题分解为核心意图。

【问题讨论】:

  • 可能有数百个 try-catch-finally 块写入应用程序 servlet。你的问题到底是什么意思?
  • 我想知道在 JVM 未关闭时已经输入了相应的 try 块时,finally 中的代码是如何不执行的。从引用中,我了解到即使不调用Thread.kill,线程也是可能的。我想知道 servlet 容器是否有办法关闭 Web 应用程序,这样我就不能依赖 finally 被执行。
  • 如教程和可能的 dup Q/A 中所述,执行finally 的唯一方法是 JVM 停止。这是通过执行System.exit(0); 或JVM 崩溃。
  • @LuiggiMendoza 是的。但关键是,是的,最终可以被打断(如果你正在做一些愚蠢和疯狂的事情)。 OP看到我的答案。也许这有帮助。

标签: java multithreading exit


【解决方案1】:

好吧,我的立场是正确的。可以通过使用不推荐使用的方法:

@Test
public void testThread() throws Exception {
    Thread thread = new Thread(new MyRunnable());
    thread.start();
    Thread.sleep(100);
    thread.suspend();
    Thread.sleep(2000);
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Start");
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("Done");
        }
    }
}

由于线程休眠时(很可能)会发生暂停,finally 块将永远不会被执行。

【讨论】:

  • 看起来在 java8 上挂起不会中断睡眠。无法复制
【解决方案2】:

Rafael,我相信这是您所追求的边缘案例之一。如果线程在本机的某些东西上被阻塞(例如从STDINSocket 读取),并且JVM 处于关闭状态,并且线程被中断,那么finally 可能不会被调用。

以下示例在不调用已弃用方法的情况下表明了这一点:

  1. Sleep - 终于调用了。
  2. SystemIn - 最后没有被调用。

这个例子非常做作,纯粹是为了演示目的:)

public class Interrupted {

  static final List<Thread> THREADS = Arrays.asList(
      new Thread(new Sleep()),
      new Thread(new SystemIn())
  );
  static final CountDownLatch LATCH = new CountDownLatch(THREADS.size());

  public static void main(String[] args) throws Exception {
    Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook()));
    for (Thread thread : THREADS) {
      thread.start();
    }
    System.out.println("[main] Waiting for threads to start...");
    LATCH.await();
    System.out.println("[main] All started, time to exit");
    System.exit(0);
  }

  static abstract class BlockingTask implements Runnable {
    @Override
    public void run() {
      final String name = getClass().getSimpleName();
      try {
        LATCH.countDown();
        System.out.printf("[%s] is about to block...%n",name);
        blockingTask();
      } catch (Throwable e) {
        System.out.printf("[%s] ", name);
        e.printStackTrace(System.out);
      } finally {
        System.out.printf("[%s] finally%n", name);
      }
    }
    abstract void blockingTask() throws Throwable;
  }

  static class Sleep extends BlockingTask {
    @Override
    void blockingTask() throws Throwable {
      Thread.sleep(60 * 60 * 1000); // 1 hour
    }
  }

  static class SystemIn extends BlockingTask {
    @Override
    void blockingTask() throws Throwable {
      System.in.read();
    }
  }

  static class ShutdownHook implements Runnable {
    @Override
    public void run() {
      System.out.println("[shutdown-hook] About to interrupt blocking tasks...");
      for (Thread thread : THREADS) {
        thread.interrupt();
      }
      System.out.println("[shutdown-hook] Interrupted");
      try {
        for (int i=0; i<10; i++) {
          Thread.sleep(50L);
          System.out.println("[shutdown-hook] Still exiting...");
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

}

【讨论】:

  • 我不这么认为。上面的代码立即触发中断,操作系统在那个时间点并没有(太多)等待。另外,我在之后的一段时间内保持关闭挂钩。
  • 如果你根本不打断,finally 仍然不会被调用。 exit() 不会等待 1 小时睡眠,它会被杀死。无论如何,我学到了一些关于 CountDownLatch 的知识,干杯!
猜你喜欢
  • 1970-01-01
  • 2010-12-02
  • 2017-01-23
  • 2019-04-06
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 2011-03-24
  • 2012-05-02
相关资源
最近更新 更多