当ThreadLocal遇上Tomcat线程池

5 篇文章 0 订阅
5 篇文章 0 订阅

Java开发中,我们一般使用ThreadLocal来传递当前请求域的持久变量,比如sessiontoken、用户信息等。

但是,当选择Tomcat做服务容器时,可能会出现ThreadLocal传递的持久变量错乱。
原因是Tomcat内部实现了线程池,存在线程复用问题。

例如:
现有abc三个空闲线程
1、request-1进来,分配了a线程去处理,存入ThreadLocal变量
2、很快request-2也来了,此时a线程尚未处理完成,只能分配bc之一去处理
3、request-3也来了,此时a线程已经处理完成,分配a线程去处理,因某些原因(参数失效等)不存入ThreadLocal变量,但是由于a线程刚刚处理完request-1,之前的变量仍有效,所以request-3进来后虽未存入变量,但仍能获取到数据
这就导致了数据错乱

解决办法:

请求处理完成后,务必手动对ThreadLocal变量进行清理操作

拦截器实现:

@Component
public class LocalInterceptor implements HandlerInterceptor {

    private final UserThreadLocal local;

    public LocalInterceptor(UserThreadLocal local) {
        this.local = local;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String user = request.getParameter("user");
        // user 有效时才存入 ThreadLocal 中,否则直接略过
        if (null != user && !"".equals(user)) {
            local.set(user);
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 必须 remove
        // 避免因容器线程池复用导致 ThreadLocal 错乱问题
        local.remove();
    }
}

如此,可解!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值