关于JVM中运行的应用程序何时被关闭退出呢

最近在调研一个分布式分片的任务调度框架的事情, 接触到了 Xxl-job, 在运行这个项目的服务案例时, 作者提供了一个spring-web形式的案例工程, clone到本地编译运行确实没有问题, 同时也部署了中心化管理服务Xxl-job-admin, 还用手动即时触发的方式调度了执行器服务中的任务逻辑;
然后在查阅项目文档时, 作者说明了执行器服务内部是启动了Jetty服务器与调度中心进行通信, 这里就有疑惑了, 既然是内部Jetty通信的方式, 那为何还要以servlet-web项目的形式部署到tomcat容器中呢?直接打包执行器项目为jar, 以普通java应用的方式启动不是更方便吗

通常我们运行一个java程序, 是从一个类的main方法为入口。背后就是JVM启动一个独立的非守护线程(non-daemon), 去执行我们的 static main 方法, 当出现以下情况, 应用程序线程就会被JVM关闭结束掉;

  1. 应用程序main方法执行完成并返回后, 应用内不存在其他用户线程, JVM就会关闭结束应用
  2. 应用程序内部调用System.exit(0);, 这样无论应用内是否存在用户线程, 守护线程, 都会强制退出;

再来说说上面, 我想通过直接执行一个static main方法的启动执行器服务(基于spring的), 所以写了下面的代码

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 应用程序启动入口
 * @author Hinsteny
 * @version $ID: MyJobApplication 2018-06-29 15:01 All rights reserved.$
 */
public class MyJobApplication {

    /**
     * start spring container
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"appcontext-xxl-job.xml"});
        context.start();
        //Thread.sleep(1000);
    }

}

// "appcontext-xxl-job.xml"



	
		
		
			
				classpath*:xxl-job-executor.properties
			
		
	

    

	
	

	
	
		
		
		
		
		
		
		
		
		
		
		
		
		
		
	



然后运行发行, 应用程序执行完main函数就关闭了, 死活不能起起来后持续运行, 到底啥原因呢?

一番查找后, 大概是这样的, 上面的xml配置文件中, 是调度框架作者在执行器服务的初始化过程中启动了一个守护线程, 内部有启动jetty服务器的操作, 然后jetty内部的启动逻辑中, 又启动了一些列的守护线程(jvm退出监听的)和用户线程(监听端口的), 这样的话, 那我给主程序的main函数最后一句加一行休眠, 一秒钟已经足够jetty内部相关启动程序执行, 创建出用户线程了, 所以休眠一秒后, 虽然main方法结束退出了, 但是应用还是在持续运行啦!

给出个例子看看应用程序到底哪些情况会持续运行不退出呢

package org.hinsteny.jvm.commons;

import java.time.LocalDateTime;

/**
 * 一个运行在jvm中的应用程序, 当所有用户线程退出后, 守护线程也就退出了, 然后应用程序便会关闭结束
 * ::只要程序中有一个用户线程, 应用程序就不会被jvm关闭结束;
 * ::只要程序中只剩有一个守护线程, 应用程序就会被jvm关闭结束;
 *
 * @author Hinsteny
 * @version $ID: MyAPP 2018-06-30 13:17 All rights reserved.$
 */
public class MyAPP {

    private static final AtomicInteger flag = new AtomicInteger(1);

    private static final AtomicBoolean awaited = new AtomicBoolean(false);

    public static void main(String[] args) {
        System.out.println("starting app main tread, am i daemon " + Thread.currentThread().isDaemon());
//        startDaemonThread();
        startUserThread();
        startUserThreadLock();
        System.out.println("stop app main thread ");
//        System.exit(0);
    }

    private static void startDaemonThread() {
        Thread app = new Thread(() -> {
            System.out.println("I am daemon thread, i started");
            try {
                while (true) {
                    Thread.sleep(100000);
                    System.out.println(LocalDateTime.now());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("I am daemon thread, i am dead!!!");
        });
        app.setDaemon(true);
        app.start();
    }

    private static void startUserThread() {
        new Thread(() -> {
            System.out.println("I am user thread, i started");
            try {
                while (true) {
                    System.out.println(LocalDateTime.now());
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("I am user thread, i am dead!!!");
        }).start();
    }

    private static void startUserThreadLock() {
        new Thread(() -> {
            System.out.println("I am user thread, i started");
            synchronized (flag) {
                System.out.println(" [Dubbo] Current Spring Boot Application is await...");
                while (!awaited.get()) {
                    try {
                        flag.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
            System.out.println("I am user thread, i am dead!!!");
        }).start();
    }
}

你可能感兴趣的:(关于JVM中运行的应用程序何时被关闭退出呢)