当前位置:   article > 正文

【多线程】解决SpringBoot热部署时layering-cache线程池被Tomcat Graceful shutdown,重新赋值方法区中 StatsServi_tomcatgraceful

tomcatgraceful

解决SpringBoot热部署时layering-cache线程池被Tomcat Graceful shutdown,重新赋值方法区中 StatsService的Static ScheduledThreadPoolExecutor,以免初始化Bean时Terminated线程触发拒绝策略

SpringBoot热部署

在这里插入图片描述

Tomcat graceful shutdown(优雅停机)

1.Tomcat接受请求是通过Connector组件,而这个组件本身实现了LifeCycle接口,它是可以被暂停的,暂停过程只停止接受请求,但不会关闭容器本身
因此,优雅停机,应该是先暂停 Tomcat 的 Connector,然后再等待执行线程执行完成,最后停止。
2.同时layering-cache里StatsService的静态变量ScheduledThreadPoolExecutor也被停掉的
3.热部署 只是将最新的class 装载到另一个classloader,tomcat实际没有重启

热部署时

在这里插入图片描述
1.热部署restartedMain线程重新Initializing ExecutorService
2.重新create bean时layering-cache里用的线程池触发拒绝策略,因为此时这里的ScheduledThreadPoolExecutor处于Terminated死亡状态,该状态不能不会切换到其他任何状态。
3.线程池会拒绝任何想要加入的任务。因为这里用的还是同一个running jvm的方法区的静态变量ScheduledThreadPoolExecutor,也是Tomcat优雅停机时 shutdown掉的线程池
在这里插入图片描述

解决

思路是在create bean layeringCacheManager初始化前,使用BeanPostProcessor,获取layering-cache框架中BeanFactory的StatsService,通过反射修改静态变量ScheduledThreadPoolExecutor


import com.github.xiaolyuh.stats.StatsService;
import com.github.xiaolyuh.util.NamedThreadFactory;
import com.sun.istack.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * @Description 解决SpringBoot热部署时layering-cache线程池被Tomcat Graceful shutdown,
 *              重新赋值方法区中 StatsService的Static ScheduledThreadPoolExecutor,以免初始化Bean时Terminated线程触发拒绝策略
 * @Author fuly2
 * @date 2022-02-18 13:50
 **/
@Component
public class StatesBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements BeanFactoryAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {}

    @Override
    @Nullable
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

        if ("layeringCacheManager".equals(beanName)) {
            StatsService statsService = com.github.xiaolyuh.util.BeanFactory.getBean(StatsService.class);
            Field executor = null;
            try {
                executor = statsService.getClass().getDeclaredField("executor");
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            executor.setAccessible(true);
            try {
                ScheduledThreadPoolExecutor executor2= (ScheduledThreadPoolExecutor) executor.get(statsService);
                if (executor2.isTerminated()){
                   executor.set(statsService,new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("layering-cache-stat")));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

layering-cache

1.layering-cache是一个支持分布式环境的多级缓存框架,使用方式和spring-cache类似。
2.一级缓存使用Caffeine作为本地缓存,二级缓存使用redis作为集中式缓存。一级缓存和二级缓存的数据一致性是通过推和拉两种模式相结合的方式来实现的。推主要是基于redis的pub/sub机制,拉主要是基于消息队列和记录消费消息的偏移量来实现的。

ScheduledThreadPoolExecutor

在这里插入图片描述
Terminated是一个线程的最终状态,在该状态中线程不会切换到其他任何状态,线程进入Terminated状态,意味着该线程的整个生命周期都结束了,下列这些情况将会使线程进入Terminated状态。

  • 线程运行正常结束,结束生命周期。
  • 线程运行出错意外结束
  • JVM Crash,导致所有线程都结束。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/767538
推荐阅读
相关标签
  

闽ICP备14008679号