• ThreadLocal 应用


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

    1.可以用 request 携带数据。

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

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

    创建一个类UserThreadLocal.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();
        }
    }
    

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

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

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

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

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

    在controller 或 service 中调用

      User user = UserThreadLocal.get();
    

    实现ThreadLocal复制到新线程@Async

    方法一:

    如何在子线程和线程池中使用 ThreadLocal 传输上下文

    方法二:

    第一步:自定义Spring线程池

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

    第二步:自定义TaskDecorator

    /**
     * @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

  • 相关阅读:
    IE8上传插件jquery-form.js上传请求参数设置type为post失效问题
    路径参数汉字兼容问题
    vue-cli2移动端适配
    事件委托原生、jQuery实现
    new Date()在移动端的问题
    create-react-app配置less
    删除左右两边空格
    日期转换
    Git 常用命令
    单页面应用
  • 原文地址:https://www.cnblogs.com/kancy/p/10761273.html
Copyright © 2020-2023  润新知