java中ThreadLocal的使用

简介: 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

相关文章
|
8月前
|
存储 Java 数据安全/隐私保护
探索Java中神奇的ThreadLocal:为什么它是多线程编程的重要工具?
探索Java中神奇的ThreadLocal:为什么它是多线程编程的重要工具?
117 0
|
存储 Java
java之线程死锁和ThreadLocal的使用
java之线程死锁和ThreadLocal的使用
|
4月前
|
算法 安全 Java
JAVA并发编程系列(12)ThreadLocal就是这么简单|建议收藏
很多人都以为TreadLocal很难很深奥,尤其被问到ThreadLocal数据结构、以及如何发生的内存泄漏问题,候选人容易谈虎色变。 日常大家用这个的很少,甚至很多近10年资深研发人员,都没有用过ThreadLocal。本文由浅入深、并且才有通俗易懂方式全面分析ThreadLocal的应用场景、数据结构、内存泄漏问题。降低大家学习啃骨头的心理压力,希望可以帮助大家彻底掌握并应用这个核心技术到工作当中。
|
5月前
|
存储 安全 Java
Java 中的 ThreadLocal 变量
【8月更文挑战第22天】
45 4
|
6月前
|
存储 SQL Java
(七)全面剖析Java并发编程之线程变量副本ThreadLocal原理分析
在之前的文章:彻底理解Java并发编程之Synchronized关键字实现原理剖析中我们曾初次谈到线程安全问题引发的"三要素":多线程、共享资源/临界资源、非原子性操作,简而言之:在同一时刻,多条线程同时对临界资源进行非原子性操作则有可能产生线程安全问题。
106 1
|
7月前
|
存储 安全 Java
深入理解Java中的ThreadLocal机制:原理、方法与使用场景解析
深入理解Java中的ThreadLocal机制:原理、方法与使用场景解析
109 2
|
6月前
|
存储 缓存 Java
Java面试题:解释Java中的内存屏障的作用,解释Java中的线程局部变量(ThreadLocal)的作用和使用场景,解释Java中的锁优化,并讨论乐观锁和悲观锁的区别
Java面试题:解释Java中的内存屏障的作用,解释Java中的线程局部变量(ThreadLocal)的作用和使用场景,解释Java中的锁优化,并讨论乐观锁和悲观锁的区别
61 0
|
6月前
|
并行计算 算法 安全
Java面试题:解释Java内存模型的内存屏障,并讨论其对多线程并发的影响,解释Java中的线程局部变量(ThreadLocal)的工作原理,解释Java中的ForkJoinPool的工作原理
Java面试题:解释Java内存模型的内存屏障,并讨论其对多线程并发的影响,解释Java中的线程局部变量(ThreadLocal)的工作原理,解释Java中的ForkJoinPool的工作原理
53 0
|
6月前
|
Java 数据库连接
Java面试题:Java内存模型中的happens-before关系,Java中的ThreadLocal是如何工作的?Java中的CountDownLatch和CyclicBarrier的区别?
Java面试题:Java内存模型中的happens-before关系,Java中的ThreadLocal是如何工作的?Java中的CountDownLatch和CyclicBarrier的区别?
45 0
|
8月前
|
存储 Java
Java的ThreadLocal使用
Java的ThreadLocal使用
43 1