ThradLocal原理解析及SpringSecurity无法在子线程中获取上下文信息解决

本文深入解析ThreadLocal的工作原理,包括它的作用、实现方式及内存泄漏问题,并探讨在SpringSecurity中如何解决子线程无法获取主线程中的安全上下文信息,介绍了ContextHolder作为解决方案之一。
摘要由CSDN通过智能技术生成

ThreadLocal使用及其原理解析

一、前言


项目中使用到了SpringSecurity框架作为安全验证,但是却发现一个问题,即当在子线程中获取SecurityContextHolder中存储的对象时会报空指针异常,后来发现原来SpringSecurity默认是将对象信息存储在ThreadLocal类型的变量中,因此在子线程调用便会出现空指针异常,异常代码如下:

    public void insertFill(MetaObject metaObject) {
   
        log.info("创建时的自动插入策略生效");
        this.strictInsertFill(metaObject, SystemConfig.createTime, Date.class, new Date());
        if(loginUser == null){
   
            try {
   
                //此处会出现空指针异常
                loginUser = (AdminLoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            }catch (Exception e){
   
                log.info("用户尚未登录,自动插入策略无需生效");
            }
        }
        if (loginUser != null && loginUser.getAdminUser() != null){
   
            this.strictInsertFill(metaObject, SystemConfig.createBy, String.class, loginUser.getAdminUser().getId());
        }
    }

SpringSecurity使用ThreadLocal存储上下文信息代码如下:

	public static SecurityContext getContext() {
   
		return strategy.getContext();
	}
	
 	//默认采用就是ThreadLocal进行存储
	private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();

	public SecurityContext getContext() {
   
		SecurityContext ctx = contextHolder.get();

		if (ctx == null) {
   
			ctx = createEmptyContext();
			contextHolder.set(ctx);
		}

		return ctx;
	}

    public T get() {
   
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
   
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
   
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

因此,为了解决这一问题,打算研究一下ThreadLocal使用及其原理

二、作用


1、基本概念

ThreadLocal可以解释成线程的局部变量,也就是说一个ThreadLocal的变量只有当前自身线程可以访问,别的线程都访问不了,那么自然就避免了线程竞争。因此,ThreadLocal提供了一种与众不同的线程安全方式,它不是在发生线程冲突时想办法解决冲突,而是彻底的避免了冲突的发生

2、基本使用

创建一个ThreadLocal对象:

    public static void main(String[] args) {
   
        ThreadLocal<String> localVar = new ThreadLocal<>();
        localVar.set("hello world!!!"); //设置值为hello world!!!
        String val = localVar.get(); //在当前线程取出对应的值
        System.out.println(val); //输出结果为hello world!!!
        
        //新开线程取ThreadLocal变量的值
        Thread thread = new Thread(() -> {
   
            System.out.println(localVar.get<
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值