ThreadLocal的相关知识与应用

ThreadLocal是一个Java中的类,它提供了线程局部变量的支持。它可以用来在多线程环境下,为每个线程创建独立的变量副本,使每个线程都拥有自己的变量副本,互不影响。

使用ThreadLocal可以解决多线程之间共享变量的并发访问问题。它可以确保每个线程操作的变量是独立的,避免了线程安全问题的出现。通过ThreadLocal对象,每个线程在访问变量时都会得到自己的副本,修改副本也不会影响其他线程的副本。

ThreadLocal的常见用法是在多线程任务中保存和共享数据,例如在Web应用中保存用户会话信息、数据库连接、事务上下文等。每个线程都可以通过ThreadLocal对象获取到自己的独立副本,从而实现了线程安全的共享数据。

今天来说的相关应用是,在对用户进行登录操作后,如何得到当前登录用户的ID。在Web应用中,当用户登录后,通常会将用户的ID等信息保存在一个会话中,以便在整个会话期间进行访问。然而,在多线程环境下,不同的线程可能同时处理多个会话,所以需要一种机制来确保每个线程能够访问到自己的会话信息。

通过使用ThreadLocal,可以在用户登录时,将用户的ID保存在ThreadLocal中,这样在整个会话期间,每个线程都可以通过ThreadLocal获取自己独立的用户ID副本。

1.创建BaseContext类,用来调用ThreadLocal底层的三个方法:

package com.sky.context;

public class BaseContext {

    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    /**
     * 设置
     * @param id
     */
    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    /**
     * 获取
     * @return
     */
    public static Long getCurrentId() {
        return threadLocal.get();
    }

    /**
     * 删除
     */
    public static void removeCurrentId() {
        threadLocal.remove();
    }

}

2.在拦截器类中,加入set()和remove()方法:

 /**
     * 校验jwt
     *  在Handler之前执行。就是Controller中标记了@XxxMapping注解的方式
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            //当前登录的员工ID
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);

            //把登录ID设置到ThreadLocal上
            BaseContext.setCurrentId(empId);

            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }

    /**
     * 渲染视图之后执行。执行释放资源的操作
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //从ThreadLocal上删除登录ID
        BaseContext.removeCurrentId();
    }

3.通过以上方法,我们就可以在执行Controller方法中,通过BaseContext.getCurrentId()方法来获取到当前登录用户的ID。

我们在进行方法的执行过程中,会出现内存泄漏的情况。因此我们在ThreadLocal执行完后,使用了remove方法,就可以将ThreadLocal中存在的数据进行清理,有效地解决此问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值