即使主要功能退出后,此java程序如何保持运行? [英] How this java program keeps running even after main function exits?

查看:68
本文介绍了即使主要功能退出后,此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()使用的线程是

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.

当Java虚拟机启动时,通常只有一个非守护进程线程(通常调用某些指定类的名为 main 的方法).Java虚拟机将继续执行线程,直到发生以下两种情况之一为止:

When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:

  • 已调用类 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 发出不再接受新任务并在所有现有任务完成后终止的信号.来自

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:

启动有序关闭,在该关闭中执行先前提交的任务,但不接受任何新任务.如果已关闭,则调用不会产生任何其他影响.

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.

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

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

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

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

尝试停止所有正在执行的任务,暂停正在等待的任务的处理,并返回正在等待执行的任务的列表.

Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.

此方法不等待主动执行的任务终止.使用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程序如何保持运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆