文章目录

    • 在Map中存储用户数据
    • 在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;}@Overridepublic void run() {String userName = userRepository.getUserNameForUserId(userId);userContextPerUserId.put(userId, new Context(userName));}}

这里我们定义了一个static的Map来存取用户信息。

再看一下怎么使用:

    @Testpublic 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;}@Overridepublic 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 {@Testpublic 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@411734d4thread 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的博客

©著作权归作者所有:来自51CTO博客作者ddean2009的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. java中wait和sleep的区别
  2. java并发中的Synchronized关键词
  3. java.util.concurrent简介
  4. java并发中CountDownLatch的使用
  5. java中Locks的使用
  6. 什么是爬虫?Python爬虫工作需要掌握哪些技能?
  7. 在java中构建高效的结果缓存
  8. java中ThreadPool的介绍和使用
  9. 【Vue框架学习】组件注册、组件通信、前端路由实现原理等知识点

随机推荐

  1. android开发之设置Edittext密码的方法
  2. 【拿来主义】Android反编译工具
  3. Android(安卓)判断Root的方法
  4. Android 线程优先级设置方法
  5. Google手机操作系统Android应用开发入门
  6. Android 数据库简单操作
  7. Android缓存理解
  8. Android(安卓)frameworks中Bn*和Bp*的区
  9. Android系统启动流程 -- android
  10. Android笔记-2