0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

CTO说了,如果发现谁用kill -9关闭程序就开除

马哥Linux运维 来源:马哥Linux运维 2023-06-25 17:19 次阅读

kill -9 pid ???

kill可将指定的信息送至程序。预设的信息为SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用SIGKILL(9)信息尝试强制删除程序。程序或工作的编号可利用ps指令或jobs指令查看。

讲的这个复杂,简单点来说就是用来杀死linux中的进程,啥?你问我啥是进程?请自行百度。

我相信很多人都用过kill -9 pid这个命令,彻底杀死进程的意思,一般情况我们使用它没有上面问题,但是在我们项目中使用它就有可能存在致命的问题。

kill -9 pid 带来的问题

由于kill -9 属于暴力删除,所以会给程序带来比较严重的后果,那究竟会带来什么后果呢?

举个栗子:转账功能,再给两个账户进行加钱扣钱的时候突然断电了?这个时候会发生什么事情?对于InnoDB存储引擎来说,没有什么损失,因为它支持事务,但是对于MyISAM引擎来说那简直就是灾难,为什么?假如给A账户扣了钱,现在需要将B账户加钱,这个时候停电了,就会造成,A的钱被扣了,但是B没有拿到这笔钱,这在生产环境是绝对不允许的,kill -9 相当于突然断电的效果。

当然了,像转账这种,肯定不是使用MyISAM引擎,但是如今分布式火了起来,跨服务转账已经是很平常的事情,这种时候如果使用kill -9 去停止服务,那就不是你的事务能保证数据的准确性了,这个时候你可能会想到分布式事务,这个世界上没有绝对的安全系统或者架构,分布式事务也是一样,他也会存在问题,概率很小,如果一旦发生,损失有可能是无法弥补的,所以一定不能使用kill -9 去停止服务,因为你不知道他会造成什么后果。

在MyISAM引擎中表现的更明显,比如用户的信息由两张表维护,管理员修改用户信息的时候需要修改两张表,但由于你的kill -9 暴力结束项目,导致只修改成功了一张表,这也会导致数据的不一致性,这是小事,因为大不了再修改一次,但是金钱、合同这些重要的信息如果由于你的暴力删除导致错乱,我觉得可能比删库跑路还严重,至少删库还能恢复,你这个都不知道错在哪里。

那我们应该怎么结束项目呢?

其实java给我们提供了结束项目的功能,比如:tomcat可以使用shutdown.bat/shutdown.sh进行优雅结束。

什么叫优雅结束?

第一步:停止接收请求和内部线程。

第二步:判断是否有线程正在执行。

第三步:等待正在执行的线程执行完毕。

第四步:停止容器。

以上四步才是正常的结束流程,那springboot怎么正常结束服务呢?下面我介绍几种正常结束服务的方案,请拿好小本本做好笔记。

优雅结束服务

kill -15 pid

这种方式也会比较优雅的结束进程(项目),使用他的时候需要慎重,为什么呢?我们来看个例子

我写了一个普通的controller方法做测试

@GetMapping(value="/test")
publicStringtest(){
log.info("test---start");
try{
Thread.sleep(100000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
log.info("test---end");
return"test";
}
1234567891011

代码很简单,打印:test — start之后让让程序休眠100秒,然后再打印:test — end,在线程休眠中我们使用kill -15 pid来结束这个进程,你们猜 test — end会被打印吗?

application.yml

server:
port:9988
12

启动项目

sudo mvn spring-boot:run
1

这是maven启动springboot项目的方式

d00c9df8-11db-11ee-962d-dac502259ad0.png

看到这个就代表项目启动成了

找到项目的进程id

sudo ps -ef |grep shutdown
1

d04e15f8-11db-11ee-962d-dac502259ad0.png

这个就是项目的进程号,接下来我们先测试test接口,让线程进入休眠状态,然后再使用kill -15 14086停止项目

sudo curl 127.0.0.1:9988/test
1

回到项目日志

d09d87b4-11db-11ee-962d-dac502259ad0.png

我们发现请求已经到达服务,并且线程已经成功进入休眠,现在我们kill -15 14086结束进程

sudo kill -15 14086
1

回到日志

2020-04-2410:53:14.939INFO14086---[nio-9988-exec-1]com.ymy.controller.TestController:test---start
2020-04-2410:54:02.450INFO14086---[extShutdownHook]o.s.s.concurrent.ThreadPoolTaskExecutor:ShuttingdownExecutorService'applicationTaskExecutor'
java.lang.InterruptedException:sleepinterrupted
atjava.lang.Thread.sleep(NativeMethod)
atcom.ymy.controller.TestController.test(TestController.java:26)
atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
atjava.lang.reflect.Method.invoke(Method.java:498)
atorg.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
atorg.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
atorg.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
atorg.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
atorg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
atorg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
atorg.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
atorg.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
atjavax.servlet.http.HttpServlet.service(HttpServlet.java:634)
atorg.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
atjavax.servlet.http.HttpServlet.service(HttpServlet.java:741)
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
atorg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
atorg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
atorg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
atorg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
atorg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
atorg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
atorg.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
atorg.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
atorg.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
atorg.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594)
atorg.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
atorg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
atjava.lang.Thread.run(Thread.java:748)
2020-04-2410:54:04.574INFO14086---[nio-9988-exec-1]com.ymy.controller.TestController:test---end
2020-04-2410:54:04.610ERROR14086---[nio-9988-exec-1]o.s.web.servlet.HandlerExecutionChain:HandlerInterceptor.afterCompletionthrewexception

java.lang.NullPointerException:null
atorg.springframework.boot.actuate.metrics.web.servlet.LongTaskTimingHandlerInterceptor.stopLongTaskTimers(LongTaskTimingHandlerInterceptor.java:123)~[spring-boot-actuator-2.2.6.RELEASE.jar:2.2.6.RELEASE]
atorg.springframework.boot.actuate.metrics.web.servlet.LongTaskTimingHandlerInterceptor.afterCompletion(LongTaskTimingHandlerInterceptor.java:79)~[spring-boot-actuator-2.2.6.RELEASE.jar:2.2.6.RELEASE]
atorg.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:179)~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.servlet.DispatcherServlet.triggerAfterCompletion(DispatcherServlet.java:1427)[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atjavax.servlet.http.HttpServlet.service(HttpServlet.java:634)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atjavax.servlet.http.HttpServlet.service(HttpServlet.java:741)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)[tomcat-embed-websocket-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)[spring-boot-actuator-2.2.6.RELEASE.jar:2.2.6.RELEASE]
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594)[tomcat-embed-core-9.0.33.jar:9.0.33]
atorg.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)[tomcat-embed-core-9.0.33.jar:9.0.33]
atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)[na:1.8.0_242]
atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)[na:1.8.0_242]
atorg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)[tomcat-embed-core-9.0.33.jar:9.0.33]
atjava.lang.Thread.run(Thread.java:748)[na:1.8.0_242]

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112

d0c4a7e0-11db-11ee-962d-dac502259ad0.png

居然报错了,但是test — end是打印出来了,为什么会报错呢?这就和sleep这个方法有关了,在线程休眠期间,当调用线程的interrupt方法的时候会导致sleep抛出异常,这里很明显就是kill -15 这个命令会让程序马上调用线程的interrupt方法,目的是为了让线程停止,虽然让线程停止,但线程什么时候停止还是线程自己说的算,这就是为什么我们还能看到:test — end的原因。更多的 Spring Boot 视频教程可以关注微信订阅号码匠笔记回复 Spring Boot 获取。

ConfigurableApplicationContext colse

我们先看怎么实现

packagecom.ymy.controller;

importlombok.extern.slf4j.Slf4j;
importorg.springframework.beans.BeansException;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.ApplicationContextAware;
importorg.springframework.context.ConfigurableApplicationContext;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.PostMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
publicclassTestControllerimplementsApplicationContextAware{

privateApplicationContextcontext;

@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{
this.context=applicationContext;
}


@GetMapping(value="/test")
publicStringtest(){
log.info("test---start");
try{
Thread.sleep(100000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
log.info("test---end");
return"test";
}

/**
*停机
*/
@PostMapping(value="shutdown")
publicvoidshutdown(){
ConfigurableApplicationContextcyx=(ConfigurableApplicationContext)context;
cyx.close();
}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344

重点在:cyx.close();,为什么他能停止springboot项目呢?请看源码

publicvoidclose(){
synchronized(this.startupShutdownMonitor){
this.doClose();
if(this.shutdownHook!=null){
try{
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}catch(IllegalStateExceptionvar4){
}
}

}
}
123456789101112

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

我们看测试结果

d0e43d44-11db-11ee-962d-dac502259ad0.png

d1223c2a-11db-11ee-962d-dac502259ad0.png

很明显,他也出发了线程的interrupt方法导致线程报错,原理和kill -15差不多。

actuator

这种方式是通过引入依赖的方式停止服务,actuator提供了很多接口,比如健康检查,基本信息等等,我们也可以使用他来优雅的停机。

引入依赖


org.springframework.boot
spring-boot-starter-actuator


12345

application.yml

server:
port:9988

management:
endpoints:
web:
exposure:
include:shutdown
endpoint:
shutdown:
enabled:true
server:
port:8888
12345678910111213

我这里对actuator的接口重新给定了一个接口,这样可提高安全性,下面我们来测试一下

@RequestMapping(value="/test",method=RequestMethod.GET)
publicStringtest(){
System.out.println("test---start");
try{
Thread.sleep(10000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("test---end");
return"hello";
}
1234567891011

在请求test途中停止服务

d145519c-11db-11ee-962d-dac502259ad0.png

我们发现发送停止服务请求之后还给我们返回了提示信息,很人性化,我们看看控制台

d16b46e0-11db-11ee-962d-dac502259ad0.png

d1a8bf7a-11db-11ee-962d-dac502259ad0.png

test — end被执行了,不过在停止线程池的时候还是调用了线程的interrupt方法,导致sleep报错,这三种方式都可以比较优雅的停止springboot服务,如果我项目中存在线程休眠,我希望10秒以后再停止服务可以吗?肯定是可以的,我们只需要稍微做点修改就可以了。

1.新增停止springboot服务类:ElegantShutdownConfig.java

packagecom.ymy.config;

importorg.apache.catalina.connector.Connector;
importorg.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
importorg.springframework.context.ApplicationListener;
importorg.springframework.context.event.ContextClosedEvent;

importjava.util.concurrent.Executor;
importjava.util.concurrent.ThreadPoolExecutor;
importjava.util.concurrent.TimeUnit;

publicclassElegantShutdownConfigimplementsTomcatConnectorCustomizer,ApplicationListener<ContextClosedEvent>{

privatevolatileConnectorconnector;
privatefinalintwaitTime=10;

@Override
publicvoidcustomize(Connectorconnector){
this.connector=connector;
}

@Override
publicvoidonApplicationEvent(ContextClosedEventevent){
connector.pause();
Executorexecutor=connector.getProtocolHandler().getExecutor();
if(executorinstanceofThreadPoolExecutor){
try{
ThreadPoolExecutorthreadPoolExecutor=(ThreadPoolExecutor)executor;
threadPoolExecutor.shutdown();
if(!threadPoolExecutor.awaitTermination(waitTime,TimeUnit.SECONDS)){
System.out.println("请尝试暴力关闭");
}
}catch(InterruptedExceptionex){
System.out.println("异常了");
Thread.currentThread().interrupt();
}
}

}
}

1234567891011121314151617181920212223242526272829303132333435363738394041

2.在启动类中加入bean

packagecom.ymy;

importcom.ymy.config.ElegantShutdownConfig;
importlombok.extern.slf4j.Slf4j;
importorg.apache.catalina.connector.Connector;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
importorg.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
importorg.springframework.boot.web.servlet.server.ServletWebServerFactory;
importorg.springframework.context.ApplicationListener;
importorg.springframework.context.ConfigurableApplicationContext;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.event.ContextClosedEvent;

importjava.util.concurrent.Executor;
importjava.util.concurrent.ThreadPoolExecutor;
importjava.util.concurrent.TimeUnit;

@SpringBootApplication
publicclassShutdownServerApplication{

publicstaticvoidmain(String[]args){
ConfigurableApplicationContextrun=SpringApplication.run(ShutdownServerApplication.class,args);
run.registerShutdownHook();
}


@Bean
publicElegantShutdownConfigelegantShutdownConfig(){
returnnewElegantShutdownConfig();
}

@Bean
publicServletWebServerFactoryservletContainer(){
TomcatServletWebServerFactorytomcat=newTomcatServletWebServerFactory();
tomcat.addConnectorCustomizers(elegantShutdownConfig());
returntomcat;
}
}

1234567891011121314151617181920212223242526272829303132333435363738394041

这样我们就配置好了,我们再来测试一遍,test的接口还是休眠10秒

d1ccf8a4-11db-11ee-962d-dac502259ad0.png

我们发现这次没有报错了,他是等待了一段时间之后再结束的线程池,这个时间就是我们在ElegantShutdownConfig类中配置的waitTime。

那可能你会有疑问了,jvm没有立即停止,那这个时候在有请求会发生什么呢?如果关闭的时候有新的请求,服务将不在接收此请求。

数据备份操作

如果我想在服务停止的时候做点备份操作啥的,应该怎么做呢?其实很简单在你要执行的方法上添加一个注解即可:@PreDestroy

Destroy:消灭、毁灭 pre:前缀缩写

所以合在一起的意思就是在容器停止之前执行一次,你可以在这里面做备份操作,也可以做记录停机时间等。

新增服务停止备份工具类:DataBackupConfig.java

packagecom.ymy.config;

importorg.springframework.context.annotation.Configuration;

importjavax.annotation.PreDestroy;

@Configuration
publicclassDataBackupConfig{

@PreDestroy
publicvoidbackData(){

System.out.println("正在备份数据。。。。。。。。。。。");
}
}
123456789101112131415

我们再来测试然后打印控制台日志:

d1ed3ad8-11db-11ee-962d-dac502259ad0.png


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 程序
    +关注

    关注

    114

    文章

    3631

    浏览量

    79594
  • 引擎
    +关注

    关注

    1

    文章

    344

    浏览量

    22287
  • kill
    +关注

    关注

    0

    文章

    9

    浏览量

    2066

原文标题:CTO 说了,如果发现谁用 kill -9 关闭程序就开除

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    为什么不建议用kill-9关闭程序

    相信不少Linux运维小伙伴在实际运维中经常会用到kill -9 进程ID 这个命令来干掉程序。实际真的合理吗,今天就让我们一起来看看为什么技术牛人都不建议用kill -9关闭程序,看
    的头像 发表于 12-04 09:39 431次阅读
    为什么不建议用<b class='flag-5'>kill</b>-9<b class='flag-5'>关闭程序</b>?

    51或AVR读过12864,求程序。谢谢!

    51或AVR读过12864,求程序。谢谢!
    发表于 10-21 21:35

    转载:labview事件结构之事件过滤学习

    ;,什么意思?意思就是是否忽略该事件本身触发的结果。如果我要执行该事件对应的代码就要忽略其本身的事件结果,于是我们给discard?赋值为"T",于是有人说了,你给忽略了那我怎么关闭程序
    发表于 11-29 15:45

    动了我的电脑

    下一步:打开windows 任务管理(不会打开的,请问度娘)在PID列表中找到对应的进程 原来是QQ!!! 同样的方法,可以找到那些偷偷我们电脑的程序关闭它们,kill它们,网络速
    发表于 11-01 14:38

    新手课堂——LabVIEW事件结构(二)

    忽略该事件本身触发的结果。如果我要执行该事件对应的代码就要忽略其本身的事件结果,于是我们给discard?赋值为"T",于是有人说了,你给忽略了那我怎么关闭程序呢?这就需要利用VI的属性节点或方法节点来实现了。该段代码的完成形式
    发表于 02-10 09:48

    VISA串口关闭函数有什么

    之前做了个读取串口数据的小程序老是出现2中错误 一种是发现帧错误 还有一种提示没读完数据下一组数据已经发送过来那么问题出在哪呢? 我看别人的例程里面有加串口关闭程序 他的就运行的很好 我想问下串口
    发表于 07-14 11:03

    labview 程序退出问题

    labview 和PLC 以太网模块使用TCP通信,labview 和PLC通信中强制关闭程序,由于没有运行到关闭TCP 通信程序关闭程序了,会导致PLC以太网模块报警,如何解决这个
    发表于 08-10 14:18

    如何将XY图的属性在关闭程序后恢复至以前?

    如何将XY图的属性在关闭程序后恢复至以前,我想实现的功能是:XY图身设置两个游标,在程序运行中可任意添加游标,当关闭程序下次开启时,仍为两个游标。
    发表于 12-16 15:10

    labview 为什么关闭子vi的时候,程序就直接退出了?

    我现在是运行主程序,然后弹窗弹出了一个子vi 进行设置,但是设置完,我点击确定,程序直接退出了。。。如何才能确定后,只退出子vi而不关闭程序呢?
    发表于 11-09 10:02

    Labview主程序关闭时怎样将子程序中的串口关闭程序执行完?

    如图片所示,由于”与PLC通讯“的子程序中打开串口同PLC通讯,希望当主程序关闭时能将“布尔”的TRUE值传送到“与PLC通讯”的子程序中,从而结束子
    发表于 03-30 15:48

    无偿加班竟然被开除程序员坐不住了

    无偿加班竟然被开除程序员坐不住了近日,一则《男子每天提前2小时上班,因擅自加班被开除》的新闻在网上广泛流传,令网友们大呼震惊。西班牙加泰罗尼亚东北部首府巴塞罗那,一家廉价连锁超市Lidl的经理吉恩
    发表于 11-13 11:21

    请问关闭运行的exe后,程序是怎么处理循环中的串口和队列的?

    我很好奇的是,做的程序是个死循环,用到了串口和队列,生成exe后,运行exe文件时,如果直接右上角的关闭,会直接关闭程序,那么
    发表于 06-27 17:08

    安装AD18后X2程序停止工作没有响应

    安装AD18后,经常不定时 无规律出现提示:X2程序停止工作没有响应。紧接着就自动关闭程序,频繁的自动关闭程序,严重影响了工作,由于不定时自动关闭程序,没有来得及人工保存,工作白做了。
    发表于 04-08 09:37

    以多种方式使用”kill”命令终结应用

    无论你使用哪种操作系统,你一定会遇到某个行为失常的应用,它把自己锁死并拒绝关闭。在Linux(还有Mac),你可以用一个”kill”命令强制终结它。在这个教程中,我们将展示给你多种方式使用”kill”命令终结应用。
    的头像 发表于 04-20 16:36 4782次阅读
    以多种方式使用”<b class='flag-5'>kill</b>”命令终结应用

    求求你们别再用kill -9了,这才是Spring Boot停机的正确方式!

    kill -9 pid 可以模拟了一次系统宕机,系统断电等极端情况,而kill -15 pid 则是等待应用关闭,执行阻塞操作,有时候也会出现无法关闭应用的情况(线上理想情况下,是bu
    的头像 发表于 05-15 14:56 519次阅读