ThreadLocal 应用

news/2025/2/25 10:02:05

利用threadLocal 把拦截器中的对象传递到controller或service中

1.可以用 request 携带数据。

2.更优雅的方式是用threadlocal。

请求进入tomcat 和产生响应前,都处于同一个线程中比如在一个登录拦截器中,在preHandle方法中登录成功后,放行前,想把user对象传到controller或service中,最后在拦截器的afterCompletion方法中移除。

创建一个类UserThreadLocal.java

java">public class UserThreadLocal {

    //把构造函数私有,外面不能new,只能通过下面两个方法操作
    private UserThreadLocal(){

    }

    private static final ThreadLocal<User> LOCAL = new ThreadLocal<User>(); 

    public static void set(User user){
        LOCAL.set(user);;
    }

    public static User get(){
        return LOCAL.get();
    }
}

相当于一个容器,此容器伴随着线程,线程启动,就有这个容器,销毁,容器就跟着销毁。生命周期就是这个线程。

在拦截器中,登录成功后,放行前加上

java"> //登录成功

UserThreadLocal.set(user);//将user对象放置在本地线程中,方便controller和service获取

由于tomcat 的运行机制,要及时清空threadLocal的内容,以下可以放在拦截器的afterCompletion方法中

java">/*tomcat底层 每一个请求都是一个线程,如果每一个请求都启动一个线程,性能就会降低,
 1. 于是就有了线程池,而线程池中的线程并不是真正销毁或真正启动的。
 2. 也就是说这个请求的线程是个可复用的线程,第二次请求可能还会拿到刚刚的线程,
 3. 若不清空,里面本身就有user对象,数据会错乱*/
UserThreadLocal.set(null); //清空本地线程中的user对象数据

在controller 或 service 中调用

java">  User user = UserThreadLocal.get();

实现ThreadLocal复制到新线程@Async

第一步:自定义Spring线程池

java">@Override
  public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setTaskDecorator(new UserThreadLocalTaskDecorator());
    executor.initialize();
    return executor;
  }

第二步:自定义TaskDecorator

java">/**
 * @author kancy
 * @version 1.0
 * @date 2019/4/24 11:01
 */
public class UserThreadLocalTaskDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        // 从当前线程中获取user
        User user = UserThreadLocal.get();
        Runnable newRunnable = new Runnable(){
            @Override
            public void run() {
                try{
                    // 放到新线程中
                    UserThreadLocal.set(user);
                    runnable.run();
                }finally {
                    UserThreadLocal.set(null);
                }
            }
        };
        return newRunnable;
    }
}

参考:

https://github.com/moelholm/smallexamples/tree/master/spring43-async-taskdecorator

https://moelholm.com/2017/07/24/spring-4-3-using-a-taskdecorator-to-copy-mdc-data-to-async-threads/

http://www.sohu.com/a/280604362_100270933

转载于:https://www.cnblogs.com/kancy/p/10761273.html


http://www.niftyadmin.cn/n/712896.html

相关文章

node 怎么判断前端传过来的参数对象为空?_Node 常见面试题总结

阅读本文约需要9分钟大家好&#xff0c;我是你们的导师&#xff0c;经常看我朋友圈的同学应该知道&#xff0c;我每天会在微信上给大家免费提供以下服务&#xff01;1、长期为你提供最优质的学习资源&#xff01;2、给你解决技术问题&#xff01;3、每天在朋友圈里分享优质的技…

es 多条件查询_ES优化最佳实践

原文链接https://www.jianshu.com/p/883325b7bbda1、bool 查询的 filter 筛选众所周知&#xff0c;ES中filter是不参与相关性评分的&#xff0c;所以查询子句可以被系统进行缓存&#xff0c;性能要高于普通的query查询。bool查询中支持4种子句&#xff0c;分别是filter、must、…

structs实现三种action的方法

第一种&#xff1a;一般类&#xff0c;带有public String execute()方法。 另外一种&#xff1a;继承LoginActionInterface implements Action接口的类。第三种&#xff1a;继承LoginActionSupport extends ActionSupport抽象类的类。 结构图 三个类的详细写法&#xff0c;也贴…

UVa 1583:Digit Generator

解题思路&#xff1a;打表 #include <stdio.h> #define MAXN 100005int main() {int ans[MAXN] {0};int i;for(i 1; i < 100000; i){int digitSum i, t i;while(t){digitSum t % 10;t / 10;}if(ans[digitSum] 0 || i < ans[digitSum]) ans[digitSum] i;}in…

Java——编辑、编译和运行

1.编辑Java源程序 首先&#xff0c;我们使用Eclipse集成开发环境来编辑符合某个版本语言规范的Java源程序。 ①一个Java源文件中不能多于一个publiic类&#xff0c;但是可以没有。 ②Java源程序的文件名一定与public类的类名相同。 下面我们来看一个博主编辑的Java源程序&#…

景区门票预约系统_无预约,不出游!免费景区门票赶紧预约~

端午节来了&#xff0c;大家迎来了2020年上半年的最后一个小长假。有多少小伙伴打算&#xff0c;趁着这个假期走亲访友、自驾出行&#xff0c;吃着粽子游山玩水&#xff0c;举个手~小编提醒您&#xff0c;端午假期&#xff0c;高速公路小型客车不免费&#xff01;不过好消息是&…

通过helloworld来认识下backbone

Backbone主要涉及3部分&#xff1a;model&#xff0c;collection和view。而这个框架的优势在于&#xff1a;数据与视图分离&#xff0c;通过操作model来自动更新view。 根据我的个人经验&#xff0c;直接写个简单的例子是最最直观的&#xff0c;那么从hello world开始吧&#x…

Java——静态字段和实例字段的初始化说明(概念理解+应用举例)

我们都知道&#xff0c;在Java语言中&#xff0c;有静态字段和实例字段&#xff0c;但是&#xff0c;它们两者之间的初始化是有区别的。 其中&#xff0c;需要说明的一点就是&#xff1a;静态字段由类调用&#xff0c;实例字段由对象调用&#xff01;&#xff01;&#xff01; …