ThreadLocal小试牛刀
2024-08-31 07:15:32
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
类,在完成业务逻辑处理后,在拦截器类HttpInterceptor
的afterCompletion
方法中移除我们在过滤器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 发布!
最新文章
- 几款开源的图形化Redis客户端管理软件
- java 读取Excel文件并数据持久化方法Demo
- Android平台下使用lua调用Java代码经验总结
- IL代码完结篇
- 移动端click事件延迟300ms到底是怎么回事,该如何解决?
- JAVA课程设计-计算器(201521123028 李家俊)
- H5开发中的故障
- AGC012 - E: Camel and Oases
- [转]dd命令、cp命令详解+dd命令、cp命令对比 ---delong
- 用PowerShell的命令行检查文件的校验MD5 SHA1 SHA256
- [DQN] What is Deep Reinforcement Learning
- 正则表达式(Kotlin)
- 一句话木马:ASPX篇
- Promise在await报错后,如何继续往下跑...
- windows7系统下升级到IE11时无法使用F12开发人员工具的解决办法
- ASP.NET AJAX web chat application
- Git(未完待续)
- JSP Servlet中Request与Response所有成员方法的研究
- adb client, adb server, adbd原理浅析(附带我的操作过程)
- OpenFlow, SDN, and NFV
热门文章
- MyBatis 插件使用-简单的分页插件
- 品Spring:注解之王@Configuration和它的一众“小弟们”
- CentOS 7上编写自定义系统审计规则
- 死磕 java同步系列之zookeeper分布式锁
- 阿里云服务器CentOS6.9安装SVN
- Linux 常用解压和压缩命令
- mysql5.7初始密码及设置问题
- 02-head标签
- docker 更新后出现 error during connect
- centos7编译安装LNMP(nginx-1.16.0,mysql8.0.16,php-7.3.6)常见问题报错及解决方法