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,控制台输出

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

ThreadLocal小试牛刀的更多相关文章

  1. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

  2. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  3. Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用(后续)

    在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]里面提到了Microsoft 身份认证,其实这也是一大块需要注意的地方,特作为后续补充这些知识点.上章是使用了Microsof ...

  4. Threadlocal使用Case

    Threadlocal能够为每个线程分配一份单独的副本,使的线程与线程之间能够独立的访问各自副本.Threadlocal 内部维护一个Map,key为线程的名字,value为对应操作的副本. /** ...

  5. 多线程映射工具——ThreadLocal

    ThreadLocal相当于一个Map<Thread, T>,各线程使用自己的线程对象Thread.currentThread()作为键存取数据,但ThreadLocal实际上是一个包装了 ...

  6. ThreadLocal 工作原理、部分源码分析

    1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...

  7. ThreadLocal<T>的是否有设计问题

    一.吐槽 ThreadLocal<T>明显是.NET从JAVA中来的一个概念,但是这种设计是否出现了问题. 很明显,在JAVA中threadLocal直接是Thread的成员,当然随着th ...

  8. 理解ThreadLocal —— 一个map的key

    作用: 当工作于多线程中的对象使用ThreadLocal维护变量时,threadLocal为每个使用该变量的线程分配一个独立的变量副本. 接口方法: protected T initialValue( ...

  9. JavaSe:ThreadLocal

    JDK中有一个ThreadLocal类,使用很方便,但是却很容易出现问题.究其原因, 就是对ThreadLocal理解不到位.最近项目中,出现了内存泄漏的问题.其中就有同事在使用ThreadLocal ...

随机推荐

  1. 设计时数据源:在PostgreSql 数据查询中使用参数过滤

    在上一篇文章中,我们学习了如何设计时连接PostgreSQL 数据库及环境搭建.本节我们来学习使用PostgreSql 数据源时,创建数据集时带参数过滤的查询语句写法. 在报表中包含两种参数,可参考博 ...

  2. WKWebView针对于Cordova的IOS平台性能提升

    使用cordova做跨平台开发已久,针对于Android的性能与页面渲染问题仍然让人头疼,因为仍然有一部分人使用性能一般的手机,版本在 4.2-4.4之间,甚至都无法支持HTML5的flex布局,使得 ...

  3. 【Java基础】Java中的语法糖

    目录 Java中的语法糖 switch对String和枚举类的支持 对泛型的支持 包装类型的自动装箱和拆箱 变长方法参数 枚举 内部类 条件编译 断言 数值字面量 for-each try-with- ...

  4. @DateTimeFormat注解

    @DateTimeFormat在spring-context依赖下,所在包如下 当form表单中出现时间字段需要跟pojo对象中的成员变量进行数据绑定时,springmvc框架中的时间数据无法自动绑定 ...

  5. 网页布局——float浮动布局

    我的主要参考资料是[Object object]的文章 float 布局应该是目前各大网站用的最多的一种布局方式了,但是也特别复杂,这里详细讲一下 首先,什么是浮动? 浮动元素是脱离文档流的,但不脱离 ...

  6. 网页布局——table布局

    table 的特性决定了它非常适合用来做布局,并且表格中的内容可以自动居中,这是之前用的特别多的一种布局方式 而且也加入了 display:table;dispaly:table-cell 来支持 t ...

  7. C语言I作业004

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 作业 我在这个课程的目标是 掌握使用for循环语句实现指定次数的循环程序设计 这个作业在那个具体方面帮助我实现目标 pta运用for循环语 ...

  8. Redis 复制过程详解

    Redis 的复制功能分为同步( sync )和命令传播( command propagate )两个步骤: 同步用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态. 命令传播则用于在主服务 ...

  9. 【包教包会】Chrome拓展开发实践

    首发于微信公众号<前端成长记>,写于 2019.10.18 导读 有句老话说的好,好记性不如烂笔头.人生中,总有那么些东西你愿去执笔写下. 本文旨在把整个开发的过程和遇到的问题及解决方案记 ...

  10. js仓库。。。

    <script type="text/javascript" src="//ra.revolvermaps.com/0/0/8.js?i=0ln1fndtptz&a ...