zoukankan      html  css  js  c++  java
  • ThreadLocal小试牛刀

    ThreadLocal中保存的数据只能被当前线程私有,不被其它线程可见

    证明

    声明一个全局的变量threadLocal,初始值为1,通过3个线程对其进行访问修改设置,理论上threadLocal的最终值应该是6,然而我们的输出结果是3,说明了threadLocal中存放的数据是各自线程私有的

    package com.mmall.concurrency.example.threadLocal;
    
    public class UseThreadLocal {
        static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
            @Override
            protected Integer initialValue() {
                return 1;
            }
        };
    
    
        //运行3个线程
        public void startThreadArray() {
            Thread[] thread = new Thread[3];
            for (int i = 0; i < thread.length; i++) {
                thread[i] = new Thread(new MyThread(i));
            }
    
            for (int i = 0; i < thread.length; i++) {
                thread[i].start();
            }
        }
    
        private class MyThread implements Runnable {
            int id;
    
            public MyThread(int i) {
                id = i;
            }
    
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":start");
                Integer v = threadLocal.get();
                v=v+id;
                threadLocal.set(v);
                System.out.println(Thread.currentThread().getName()+":"+threadLocal.get());
            }
        }
    
        public static void main(String[] args) {
            UseThreadLocal useThreadLocal = new UseThreadLocal();
            useThreadLocal.startThreadArray();
        }
    }
    
    

    结果

    Thread-0:start
    Thread-2:start
    Thread-1:start
    Thread-0:1
    Thread-2:3
    Thread-1:2
    

    小应用

    ThreadLocal结合过滤器和拦截器进行搭配使用,通过在过滤器HttpFilter设置ThreadLocal中的值,通过拦截器HttpInterceptor移除拦截器中的值

    编写`ThreadLocal类,包含设置、获取、移除操作

    package com.mmall.concurrency.example.threadLocal;
    
    public class RequestHolder {
    
        private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();
    
        public static void add(Long id) {
            requestHolder.set(id);
        }
    
        public static Long getId() {
            return requestHolder.get();
        }
    
        public static void remove() {
            requestHolder.remove();
        }
    }
    
    

    编写过滤器HttpFilter类,通过在doFilter方法中对ThreadLocal进行存数据

    package com.mmall.concurrency;
    
    import com.mmall.concurrency.example.threadLocal.RequestHolder;
    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    @Slf4j
    public class HttpFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            log.info("do filter, {}, {}", Thread.currentThread().getId(), request.getServletPath());
            RequestHolder.add(Thread.currentThread().getId());
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    

    编写ThreadLocalController类,在业务中可以获取到在过滤器HttpFilter中对ThreadLocal中存放的数据

    package com.mmall.concurrency.example.threadLocal;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    @RequestMapping("/threadLocal")
    public class ThreadLocalController {
    
        @RequestMapping("/test")
        @ResponseBody
        public Long test() {
            return RequestHolder.getId();
        }
    }
    
    

    编写拦截器HttpInterceptor类,在完成业务逻辑处理后,在拦截器类HttpInterceptorafterCompletion方法中移除我们在过滤器HttpFilter中对ThreadLocal设置的值

    package com.mmall.concurrency;
    
    import com.mmall.concurrency.example.threadLocal.RequestHolder;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Slf4j
    public class HttpInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            log.info("preHandle");
            return true;
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            RequestHolder.remove();
            log.info("afterCompletion");
            return;
        }
    }
    
    

    编写springboot的启动类ConcurrencyApplication,实例化了FilterRegistrationBean

    package com.mmall.concurrency;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @SpringBootApplication
    public class ConcurrencyApplication extends WebMvcConfigurerAdapter{
    
    	public static void main(String[] args) {
    		SpringApplication.run(ConcurrencyApplication.class, args);
    	}
    
    	@Bean
    	public FilterRegistrationBean httpFilter() {
    		FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    		registrationBean.setFilter(new HttpFilter());
    		registrationBean.addUrlPatterns("/threadLocal/*");
    		return registrationBean;
    	}
    
    	@Override
    	public void addInterceptors(InterceptorRegistry registry) {
    		registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
    	}
    }
    
    

    启动springboot启动类,访问http://localhost:8080/threadLocal/test,控制台输出

    1571820790890

    本文由博客一文多发平台 OpenWrite 发布!

  • 相关阅读:
    一起学Vue之表单输入绑定
    简单易懂的单元测试框架-gtest(二)
    简单易懂的单元测试框架-gtest(一)
    最常用设计模式-模板方法模式
    最常用设计模式-简单工厂模式
    最常用设计模式-单例模式
    端口复用后门
    内存取证工具-volatility、foremost
    python的exe反编译
    Linux加密known_hosts文件中的IP
  • 原文地址:https://www.cnblogs.com/lisingshen/p/11782271.html
Copyright © 2011-2022 走看看