2021-05-13 如何结束服务

kill -9 pid 存在的问题

kill -9 pid 彻底杀死进程

kill -9 属于暴力删除,会给程序带来比较严重的后果

优雅结束

第一步:停止接收请求和内部线程。第二步:判断是否有线程正在执行。第三步:等待正在执行的线程执行完毕。第四步:停止容器。

在Java中,tomcat可以使用 shutdown.bat/shutdown.sh进行优雅结束

springboot 中结束服务方案

【方案一】kill -15 pid

@RestController
@RequestMapping("/finish")
@Slf4j
public class TestFinishController {

    @GetMapping("/test")
    public String test(){
        log.info("-----test   start------");
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("-----test   end--------");
        return "test";
    }
}

启动项目

找到项目进程id

sudo ps -ef |grep xxx

在这里插入图片描述
测试test接口,让线程进入休眠状态

sudo curl 127.0.0.1:8088/finish/test

在这里插入图片描述
结束进程

sudo kill -15 xxx

在这里插入图片描述
报错原因:
在线程休眠期间,当调用线程的interrupt方法的时候会导致sleep抛出异常(此时kill -15 命令会让程序马上调用线程的interrupt方法)

目的是为了让线程停止,虽然让线程停止,但线程什么时候停止还是线程自己说的算,这就是为什么我们还能看到:test — end的原因

2021-05-13 10:39:51.708  INFO 90521 --- [nio-8088-exec-5] c.s.d.controller.TestFinishController    : -----test   start------
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.springboottest.demo01.controller.TestFinishController.test(TestFinishController.java:17)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
2021-05-13 10:40:30.785  INFO 90521 --- [nio-8088-exec-5] c.s.d.controller.TestFinishController    : -----test   end--------
2021-05-13 10:40:30.928  INFO 90521 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2021-05-13 10:40:30.936  INFO 90521 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource   : {dataSource-0} closing ...
Disconnected from the target VM, address: '127.0.0.1:58995', transport: 'socket'

Process finished with exit code 143 (interrupted by signal 15: SIGTERM)

【方案二】ConfigurableApplicationContext colse

也出发了线程的interrupt方法导致线程报错

@RestController
@RequestMapping("/finish")
@Slf4j
public class TestFinishController implements ApplicationContextAware {

    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    @GetMapping("/test")
    public String test(){
        log.info("-----test   start------");
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("-----test   end--------");
        return "test";
    }

    @PostMapping("/shutdown")
    public void shutdown(){
        ConfigurableApplicationContext cyx =(ConfigurableApplicationContext) context;
        cyx.close();
    }

}

程序在启动的时候向jvm注册了一个关闭钩子,我们在执行colse方法的时候会删除这个关闭钩子,jvm就会知道这是需要停止服务。

【方案三】actuator

引入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.properties

management.endpoints.web.exposure.include=shutdown
management.endpoint.shutdown.enabled=true
management.server.port=8888

测试
在这里插入图片描述
停止线程池的时候还是调用了线程的interrupt方法,导致sleep报错

参考文章:
为什么不建议用kill -9 关闭程序 https://mp.weixin.qq.com/s/2ndaUhYe6rwAkdj5V8BTWQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值