本文介绍了即使主要功能退出后,此java程序如何保持运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习Java的并发API.下面是一个示例程序.

I am trying to learn the concurrency API of java. Below is a sample program.

    class WaitTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executorService = null;
        try {
            executorService = Executors.newSingleThreadExecutor();
            Future<?> future = executorService.submit(() ->
                {
                    for (int i = 0; i < 100; i++) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("Printing " + i);
                    }
                });
            future.get(5, TimeUnit.SECONDS);
            System.out.println("Reached successfully");
        } finally {
            if (executorService != null) {
                executorService.shutdown();
            }
        }
    }
}

提供给ExecutorService的Runnable任务需要10秒钟才能完成.我将超时设置为5秒,以从将来的对象获取结果.显然,由于抛出了TimeoutException,主要方法在5秒钟后退出.但是即使主方法退出后,Runnable任务仍继续执行.

The Runnable task being provided to the ExecutorService takes 10 seconds to complete. I have set a timeout of 5 seconds to get the result from the future object. So obviously the main method is exiting after 5 seconds because of the TimeoutException being thrown. But the Runnable task keeps on executing even after main method exits.

这里是输出.

Printing 0
Printing 1
Printing 2
Printing 3
Printing 4
Printing 5
Printing 6
Printing 7
Printing 8
Printing 9
Printing 10
Printing 11
Printing 12
Printing 13
Printing 14
Printing 15
Printing 16
Printing 17
Printing 18
Printing 19
Printing 20
Printing 21
Printing 22
Printing 23
Printing 24
Printing 25
Printing 26
Printing 27
Printing 28
Printing 29
Printing 30
Printing 31
Printing 32
Printing 33
Printing 34
Printing 35
Printing 36
Printing 37
Printing 38
Printing 39
Printing 40
Printing 41
Printing 42
Printing 43
Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:205)
    at ocp.WaitTest.main(ConcurrencyTest.java:89)
Printing 44
Printing 45
Printing 46
Printing 47
Printing 48
Printing 49
Printing 50
Printing 51
Printing 52
Printing 53
Printing 54
Printing 55
Printing 56
Printing 57
Printing 58
Printing 59
Printing 60
Printing 61
Printing 62
Printing 63
Printing 64
Printing 65
Printing 66
Printing 67
Printing 68
Printing 69
Printing 70
Printing 71
Printing 72
Printing 73
Printing 74
Printing 75
Printing 76
Printing 77
Printing 78
Printing 79
Printing 80
Printing 81
Printing 82
Printing 83
Printing 84
Printing 85
Printing 86
Printing 87
Printing 88
Printing 89
Printing 90
Printing 91
Printing 92
Printing 93
Printing 94
Printing 95
Printing 96
Printing 97
Printing 98
Printing 99

有什么主意吗?

推荐答案

发生了一些事情.首先, Executors.newSingleThreadExecutor()使用的线程是 非守护程序 线程.正如 Thread 的文档所述,非守护程序线程将使JVM保持活动状态.

There are a few things going on. First, the threads used by Executors.newSingleThreadExecutor() are non-daemon threads. As the documentation of Thread mentions, non-daemon threads will keep the JVM alive.

  • 已调用类 Runtime exit 方法,并且安全管理器已允许进行退出操作.
  • 不是所有守护进程线程的所有线程都已死亡,要么通过从调用返回到 run 方法,要么抛出传播到 run 方法之外的异常./li>
  • The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
  • All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

第二, ExecutorService.shutdown()不会取消任何排队的或当前正在执行的任务.这仅仅是向 ExecutorService 发出不再接受新任务并在所有现有任务完成后终止的信号.来自 Javadoc :

Second, ExecutorService.shutdown() doesn't cancel any queued or currently executing tasks. It's merely a signal to the ExecutorService to no longer accept new tasks and to terminate once all existing tasks have completed. From the Javadoc:

此方法不等待先前提交的任务完成执行.使用awaitTermination可以做到这一点.

This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.

如果您想立即尝试终止 ExecutorService ,则必须使用 ExecutorService.shutdownNow() .

If you want to try and terminate the ExecutorService immediately you must use ExecutorService.shutdownNow().

此方法不等待主动执行的任务终止.使用awaitTermination可以做到这一点.

This method does not wait for actively executing tasks to terminate. Use awaitTermination to do that.

除了尽力而为后,无法保证停止处理主动执行的任务.例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止.

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.

正如Javadoc所述,不能保证即使使用 shutdownNow ,正在执行的任务也会终止.开发人员必须对任务进行编码以响应中断.

As the Javadoc states, there is no guarantee the executing tasks will terminate even with shutdownNow. The developer must code the task to respond to interruptions.

这导致第三件事:您的任务对中断没有响应.当线程被中断时, Thread.sleep 会抛出一个 InterruptedException ;当抛出该异常时,您就不会脱离循环.您的代码只打印堆栈跟踪,然后继续进行下一个迭代.要解决此问题,请在 catch 块的末尾添加 break 语句.

This leads to the third thing: Your task doesn't respond to interruptions. While Thread.sleep will throw an InterruptedException when the thread is interrupted you don't break out of the loop when said exception is thrown; your code simply prints the stack trace then continues onto the next iteration. To fix this add a break statement at the end of the catch block.

您还可以选择通过 Executors.newSingleThreadExecutor(ThreadFactory)使用自定义的 ThreadFactory .如果您拥有工厂返回的 daemon 线程,那么一旦主返回,JVM将退出.

You also have the option of using a custom ThreadFactory via Executors.newSingleThreadExecutor(ThreadFactory). If you have your factory return daemon threads then the JVM will exit once main returns.

这篇关于即使主要功能退出后,此java程序如何保持运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 07:30