java中ThreadLocal的使用
java中ThreadLocal的使用
ThreadLocal主要用来为当前线程存储数据,这个数据只有当前线程可以访问。
在定义ThreadLocal的时候,我们可以同时定义存储在ThreadLocal中的特定类型的对象。
ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
上面我们定义了一个存储Integer的ThreadLocal对象。
要存储和获取ThreadLocal中的对象也非常简单,使用get()和set()即可:
threadLocalValue.set(1);
Integer result = threadLocalValue.get();
我可以将ThreadLocal看成是一个map,而当前的线程就是map中的key。
除了new一个ThreadLocal对象,我们还可以通过:
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
ThreadLocal提供的静态方法withInitial来初始化一个ThreadLocal。
ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
withInitial需要一个Supplier对象,通过调用Supplier的get()方法获取到初始值。
要想删除ThreadLocal中的存储数据,可以调用:
threadLocal.remove();
下面我通过两个例子的对比,来看一下使用ThreadLocal的好处。
在实际的应用中,我们通常会需要为不同的用户请求存储不同的用户信息,一般来说我们需要构建一个全局的Map,来根据不同的用户ID,来存储不同的用户信息,方便在后面获取。
在Map中存储用户数据
我们先看下如果使用全局的Map该怎么用:
public class SharedMapWithUserContext implements Runnable {
public static Map<Integer, Context> userContextPerUserId
= new ConcurrentHashMap<>();
private Integer userId;
private UserRepository userRepository = new UserRepository();
public SharedMapWithUserContext(int i) {
this.userId=i;
}
@Override
public void run() {
String userName = userRepository.getUserNameForUserId(userId);
userContextPerUserId.put(userId, new Context(userName));
}
}
这里我们定义了一个static的Map来存取用户信息。
再看一下怎么使用:
@Test
public void testWithMap(){
SharedMapWithUserContext firstUser = new SharedMapWithUserContext(1);
SharedMapWithUserContext secondUser = new SharedMapWithUserContext(2);
new Thread(firstUser).start();
new Thread(secondUser).start();
assertEquals(SharedMapWithUserContext.userContextPerUserId.size(), 2);
}
在ThreadLocal中存储用户数据
如果我们要在ThreadLocal中使用可以这样:
public class ThreadLocalWithUserContext implements Runnable {
private static ThreadLocal<Context> userContext
= new ThreadLocal<>();
private Integer userId;
private UserRepository userRepository = new UserRepository();
public ThreadLocalWithUserContext(int i) {
this.userId=i;
}
@Override
public void run() {
String userName = userRepository.getUserNameForUserId(userId);
userContext.set(new Context(userName));
System.out.println("thread context for given userId: "
+ userId + " is: " + userContext.get());
}
}
测试代码如下:
public class ThreadLocalWithUserContextTest {
@Test
public void testWithThreadLocal(){
ThreadLocalWithUserContext firstUser
= new ThreadLocalWithUserContext(1);
ThreadLocalWithUserContext secondUser
= new ThreadLocalWithUserContext(2);
new Thread(firstUser).start();
new Thread(secondUser).start();
}
}
运行之后,我们可以得到下面的结果:
thread context for given userId: 1 is: com.flydean.Context@411734d4
thread context for given userId: 2 is: com.flydean.Context@1e9b6cc
不同的用户信息被存储在不同的线程环境中。
注意,我们使用ThreadLocal的时候,一定是我们可以自由的控制所创建的线程。如果在ExecutorService环境下,就最好不要使用ThreadLocal,因为在ExecutorService中,线程是不可控的。
本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/ThreadLocal
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
更多教程请参考 flydean的博客
相关文章
- java虚拟机学习-Java常量池理解与总结(13-2)
- Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring
- Java反射机制剖析(一)-定义和API
- Java JDBC 数据源
- Java final修饰符
- Win10 JAVA安装及环境搭建(windows jdk,windows java环境配置)
- Android 高德地图SDK在API 31以上崩溃的问题 GLMapEngine.destroyAMapEngine(GLMapEngine.java:1851)
- Java自学指南七、规划
- 黄山归来不看岳:《Java开发手册(黄山版)》新增 11 条规约
- Akka与Java内存模型的关系
- Java: mysql-connector-java
- Java并发JUC(java.util.concurrent)JMM内存模型
- Ubuntu安装java的几种方式以及多个JAVA版本的切换
- 【Java】java的内存浅析
- 07 Java的方法 何谓方法
- Java开发环境的搭建以及使用eclipse从头一步步创建java项目
- 第70节:Java中xml和tomcat
- 第七节:详细讲解Java中的日期,java.util.date
- Java基础语法:1.第一个java程序
- java编写二叉树以及前序遍历、中序遍历和后序遍历 .
- java高级用法之:在JNA中将本地方法映射到JAVA代码中
- Java——ThreadLocal的使用
- Java_java动态编译整个项目,解决jar包找不到问题
- Java之throw和throws的区别及java中的异常处理
- Java高手速成 | EL表达式语言
- 【JAVA】【NIO】10、Java NIO ServerSocketChannel
- Java语言基础细节归纳
- Java小白入门200例62之java中日期查询常用实例
- java中<<、>>、>>>
- java中原生的发送http请求(无任何的jar包导入)
- 【Java笔记】配置文件java.util.Properties类的使用
- 解决Java使用response下载文件报错,并总结可能出错的原因: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。