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