java高并发(九)线程封闭

线程封闭与ThreadLocal
本文探讨了线程封闭的概念,介绍了如何通过ThreadLocal实现线程间的隔离,以解决并发问题。通过实例展示了如何在服务器请求处理中使用ThreadLocal存储和获取线程本地数据,提高代码设计效率。

上一节介绍了不可变对象,通过在某些情况下将不会修改的类对象设计成不可变对象,来让对象在多个线程间保证对象是线程安全的。归根到底,相当于躲避开了并发问题,实现好的并发是一件很困难的事情,所以很多时候都想躲避并发,避免并发除了设计成不可变对象其实还有一个简单的方法就是线程封闭。

什么是线程封闭?

其实就是把对象封装到一个线程里,只有这一个线程能看到这个对象。那么这个对象就算不是线程安全的,也不会出现线程安全方面的问题了,因为他只能在一个线程里面进行访问。那么如何实现线程封闭呢?

如何实现线程封闭?

  • Ad-hoc 线程封闭:程序控制实现,最糟糕,忽略
  • 堆栈封闭:局部变量,无并发问题。是我们现实中使用最多的封闭了,简单说就是局部变量。多个线程访问一个方法的时候,方法中的局部变量都会被拷贝一份到线程栈中,所以局部变量是不会被线程共享的,因此不会出现并发问题。所以全局变量容易引起并发问题。
  • ThreadLocal线程封闭:特别好的封闭方法。ThreadLocal内部维护了一个map,key是线程的名称,value就是封闭的对象。

 ThreadLocal

正常来讲我们每一个请求对服务器来讲都是一个线程在运行,我们希望线程间隔离,一个线程在被后端服务器实际处理的时候,可以通过Filter过滤器取出当前的用户,然后将数据存放在ThreadLocal中,当线程被接口的service以及其他相关类进行处理的时候很可能需要在取出当前用户,这时就可以随时随地从ThreadLocal中直接拿到之前存储的值这样用起来就很方便了。如果我们不这样做,会有什么麻烦呢?因为我们的登录用户通常是从request中取出来的,因此需要带上request或者从request中取出来的用户信息,从controller层开始不停的往下传,甚至会传到一些util类中,这样会使得代码看起来很臃肿。当使用ThreadLocal和Filter,就可以很方便的在接口处理之前,前取出相关的信息,在接口实际处理的时候,什么时候需要什么时候再把信息取出来,这样代码在设计的时候就容易多了,不至于把request从controller一直传递下去。

具体使用实例如下:

新建一个类:

public class RequestHolder {
    //因为当前没有登录用户,我们用线程id来充当
    private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();

    /**
     * 请求进入到后端服务器,但是还没有实际处理的时候调用add,可以使用Filter
     * @param id
     */
    public static void add(Long id) {
        //虽然只传入id,但是threadLocal会取出当前线程id放到map中的key,value是传入的值
        requestHolder.set(id);
    }

    public static Long getId() {
        return requestHolder.get();
    }

    /**
     * 如果不做remove的话,会造成内存泄漏,数据永远不会释放掉
     * 需要在接口真正处理完成之后进行调用,可以使用interceptor
     */
    public static void remove() {
        requestHolder.remove();
    }
}

这个类就用来存放ThreadLocal。

新建一个Filter:

@Slf4j
public class HttpFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//        httpServletRequest.getSession().getAttribute("user");
        log.info("do filter , {}, {}", Thread.currentThread().getId(), ((HttpServletRequest) request).getServletPath());
        RequestHolder.add(Thread.currentThread().getId());
        // 如果这个Filter不想拦截住这个请求,只想做单独的数据处理时,要调用chain.doFilter,使得拦截器处理完
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

新建一个Interceptor:

@Slf4j
public class HttpInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        RequestHolder.remove();
        log.info("afterCompletion");
        return ;
    }
}

配置filter和interceptor:

@Configuration
public class Config implements WebMvcConfigurer {

    @Bean
    public FilterRegistrationBean<HttpFilter> httpFilter(){
        FilterRegistrationBean<HttpFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        // 设置filter
        filterRegistrationBean.setFilter(new HttpFilter());
        // 拦截规则
        filterRegistrationBean.addUrlPatterns("/threadLocal/*");
        return filterRegistrationBean;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
    }
}

新建一个controller进行测试:

@RestController
@RequestMapping("threadLocal")
public class ThreadLocalController {

    @GetMapping("/test")
    public Long test() {
        return RequestHolder.getId();
    }

}

在浏览器中输入localhost:8080/threadLocal/test可以输出线程的id,与后台的输出id一致。

**项目名称:** 基于Vue.js与Spring Cloud架构的博客系统设计与开发——微服务分布式应用实践 **项目概述:** 本项目为计算机科学与技术专业本科毕业设计成果,旨在设计并实现一个采用前后端分离架构的现代化博客平台。系统前端基于Vue.js框架构建,提供响应式用户界面;后端采用Spring Cloud微服务架构,通过服务拆分、注册发现、配置中心及网关路由等技术,构建高可用、易扩展的分布式应用体系。项目重点探讨微服务模式下的系统设计、服务治理、数据一致性及部署运维等关键问题,体现了分布式系统在Web应用中的实践价值。 **技术架构:** 1. **前端技术:** Vue.js 2.x、Vue Router、Vuex、Element UI、Axios 2. **后端技术:** Spring Boot 2.x、Spring Cloud (Eureka/Nacos、Feign/OpenFeign、Ribbon、Hystrix、Zuul/Gateway、Config) 3. **数据存储:** MySQL 8.0(主数据存储)、Redis(缓存与会话管理) 4. **服务通信:** RESTful API、消息队列(可选RabbitMQ/Kafka) 5. **部署与运维:** Docker容器化、Jenkins持续集成、Nginx负载均衡 **核心功能模块:** - 用户管理:注册登录、权限控制、个人中心 - 文章管理:富文本编辑、分类标签、发布审核、评论互动 - 内容展示:首页推荐、分类检索、全文搜索、热门排行 - 系统管理:后台仪表盘、用户与内容监控、日志审计 - 微服务治理:服务健康检测、动态配置更新、熔断降级策略 **设计特点:** 1. **架构解耦:** 前后端完全分离,通过API网关统一接入,支持独立开发与部署。 2. **服务拆分:** 按业务域划分为用户服务、文章服务、评论服务、文件服务等独立微服务。 3. **高可用设计:** 采用服务注册发现机制,配合负载均衡与熔断器,提升系统容错能力。 4. **可扩展性:** 模块化设计支持横向扩展,配置中心实现运行时动态调整。 **项目成果:** 完成了一个具备完整博客功能、具备微服务典型特征的分布式系统原型,通过容器化部署验证了多服务协同运行的可行性,为云原生应用开发提供了实践参考。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值