尝试块完成后,在Finally块中延迟

时间:2018-01-13 17:42:43

标签: java exception exception-handling try-catch

我正在尝试运行以下并发代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

public static void main(final String[] arguments) throws 
InterruptedException {
  ExecutorService executor = Executors.newSingleThreadExecutor();

  try {
     executor.submit(new Task());
     System.out.println("Shutdown executor");
     executor.shutdown();
     executor.awaitTermination(5, TimeUnit.SECONDS);
  } catch (InterruptedException e) {
     System.err.println("tasks interrupted");
  } finally {

     if (!executor.isTerminated()) {
        System.err.println("cancel non-finished tasks");
     }
     executor.shutdownNow();
     System.out.println("shutdown finished");
  }
 }

static class Task implements Runnable {

  public void run() {

     try {
        int duration = 6;
        System.out.println("Running Task!");
        TimeUnit.SECONDS.sleep(duration);
     } catch (InterruptedException e) {
        e.printStackTrace();
     }
  }
  }     
}

,输出为:

Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted

根据输出,似乎最后跳过块,并且首先执行finally块之后的代码,然后执行finally块。这是否与在try / catch块完成后最终执行的代码的正常流程相矛盾?

编辑:尝试

System.out.flush();
System.err.flush();
每次打印后按照其中一个建议但仍然是相同的输出。

编辑:

我正在使用在线编译器。

1 个答案:

答案 0 :(得分:3)

我认为您希望这两条轨迹相反,因为它们是以相反的顺序声明的:

  

关闭完成

     

取消未完成的任务

我认为问题来自于System.errSystem.out的混合 这些不是相同的流。因此,他们的刷新和他们的显示可以在不同的时间执行。

根据显示输出的应用程序/系统(IDE,OS命令行,在线编译器/执行程序),至少有两件事可能会产生排序问题:

  • 可能启用或未启用这些流的 autoflush
  • 跟踪的显示顺序可能不会在"输出/控制台"中的这两个流之间同步。应用程序/系统。

根据时间线显示输出的解决方法:

  • 在每次System.out.flush()调用后刷新流(System.err.flush()print())。
    它可能有效但不能保证作为写入输出的应用程序/系统可能无法通过时间线同步显示这两个流。

  • 尝试仅使用System.out并仅在程序退出的错误情况下使用System.err。 它将减少交错的可能性。

  • 如果最后一个想法不合适,因为清楚地区分这两种输出很重要,使用一个日志库(Logback或Log4j2,最好是在外观中使用SLF4J),它允许精确地跟踪信息(日期,时间) ,严重性级别,...)并按程序流程时间轴的实际顺序读取它们。

以下是仅使用System.out的相同代码:
我添加了//1//2,...评论输出的预期顺序。

public class TestThread {

    public static void main(final String[] arguments) throws InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        try {
            executor.submit(new Task());
            System.out.println("Shutdown executor"); // 1
            executor.shutdown();
            executor.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            System.out.println("tasks interrupted"); // not invoked because caught in Task.run()
        } finally {

            if (!executor.isTerminated()) {
                System.out.println("cancel non-finished tasks"); // 3
            }
            executor.shutdownNow();
            System.out.println("shutdown finished"); // 4
        }
    }

    static class Task implements Runnable {

        public void run() {

            try {
                int duration = 6;
                System.out.println("Running Task!");  // 2
                TimeUnit.SECONDS.sleep(duration);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

输出现在符合预期,在程序运行的任何地方都应该相同:命令行,IDE,......

  

关闭执行程序

     

跑步任务!

     

取消未完成的任务

     

关闭完成

     

java.lang.InterruptedException:sleep interrupted

请注意:

  

java.lang.InterruptedException:sleep interrupted

可能仍然有所不同,因为Throwable.printStackTrace()依据system.err撰写。