ThreadLocal简单理解

本文深入解析了Java中的ThreadLocal机制,探讨其如何确保线程安全,特别是在多线程环境中避免共享可变单例或全局变量所带来的问题。通过具体的JDBC Connection应用示例,展示了ThreadLocal在实际开发中的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


印象中在看书的时候见到过ThreadLocal,但突然就想不起它的用处了。。心里一惊感觉当时书白看了。于是马上网上查了查。

 
原来它的意思是线程的本地变量,ThreadLocal更像是一个线程变量访问的工具类。
 
那为什么要用这种方法呢?
翻看了《Java并发编程实践》,看到这么一个说法:线程本地变量通常用于防止可变单例或者全局变量的设计中,出现不正确的共享。
 
感觉这个看着很生硬啊。书中也举了例子,是JDBC的Connection的应用。Connection对于单线程的程序中,一般会启动时就创建好,这样就不用每次都创建对象啦。但是换到多线程环境下就不行了,因为JDBC规范并没有要求Connection是线程安全的。那么如果要解决就可以使用ThreadLocal。使用ThreadLocal可以在每个线程中创建一个Connection对象,这样就满足线程安全要求了。
 
这里比较好奇的是ThreadLocal是如何做到这些的呢?
 
ThreadLocal的实现
打开源代码,ThreadLocal是个泛型类,里面也并不复杂,看到的构造函数也是什么也没有做。ThreadLocal中比较常用的方法主要是set和get。最主要的奥秘便是下面这几行代码:
private final int threadLocalHashCode = nextHashCode();
 
    /**
     * The next hash code to be given out. Updated atomically. Starts at
     * zero.
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();
 
    /**
     * The difference between successively generated hash codes - turns
     * implicit sequential thread-local IDs into near-optimally spread
     * multiplicative hash values for power-of-two-sized tables.
     */
    private static final int HASH_INCREMENT = 0x61c88647;
 
    /**
     * Returns the next hash code.
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

threadLocalHashCode这个变量会随着ThreadLocal构造时创建,而初始化它的是一个nextHashCode()方法。从nextHashCode方法便知道是对一个整形变量nextHashCode进行了一个加法运算,而是固定的增加HASH_INCREMENT大小。

 
这样做是什么意思呢?其实就是每次创建ThreadLocal时都产生一次新的hash值,就是让每次的对象不一样。那么有何用处?
 
再看看set方法,因为这个方法是ThreadLocal将变量设置到线程中的方法:
/**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

可以看到方法的执行过程:

1、获得当前线程的实例
2、然后从线程里获取ThreadLocalMap对象,这就是线程里存本地变量的地方
3、如果map不为空则将value写入到map中,而key就是当前ThreadLocal的对象
4、如果为null,刚创建map,当然同样会将value写入map中,key同样是ThreadLocal的对象
 
这样就理解了,其实ThreadLocal每次产生一个新的对象,以此来保证每个线程都针对一个ThreadLocal对象。然后将数据通过set方法向线程中的threadLocals写入值,以此来保证线程安全。当然在写入的value必须不是一个共享对象,否则也是无法保证一定线程安全的。
 
 
引用:
《java并发编程实践》
正确理解ThreadLocal: http://www.iteye.com/topic/103804
 
 
 
注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错请点击下右下角的推荐,非常感谢!
http://www.cnblogs.com/5207

转载于:https://www.cnblogs.com/5207/p/5795624.html

### ThreadLocal 概念 `ThreadLocal` 是一种特殊的变量,在每个线程中都有独立的副本,这些副本仅限于当前线程访问和修改。由于这种隔离特性,不同线程之间不会相互影响,从而解决了多线程环境下的数据共享问题[^1]。 #### 创建与使用 `ThreadLocal` 下面是一个简单的例子展示如何定义并操作 `ThreadLocal` 变量: ```java public class Example { private static final ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>(); public void set(int value) { threadLocalValue.set(value); } public Integer get() { return threadLocalValue.get(); } } ``` 在这个案例里,每当有新的线程执行到这段代码时都会为自己分配一个新的整数类型的存储空间用于保存特定的数据值。 ### 面试常见问题 对于理解 `ThreadLocal` 的工作机制以及应用场景非常重要,以下是几个可能遇到的相关面试题目: 1. **为什么需要 `ThreadLocal`?** - 主要是为了实现线程安全的操作而设计的一种解决方案。通过给每一个线程提供自己独有的实例化对象或基本类型成员变量的方式避免了多个线程竞争同一个资源所带来的同步开销。 2. **`ThreadLocal` 是否会造成内存泄漏?** - 如果不及时清理不再使用的 `ThreadLocal` 实例,则可能导致垃圾回收器无法释放关联的对象引用链路所指向的内容,进而引发潜在的风险。因此建议在线程结束前清除掉不必要的 `ThreadLocal` 数据以防止这种情况发生。 3. **`ThreadLocal` 和锁机制有什么区别?** - 锁机制主要是为了控制对公共资源(比如文件句柄、数据库连接等)的安全并发访问;相比之下,`ThreadLocal` 则更侧重于为每个单独的工作单元——也就是各个不同的线程维护各自的状态信息而不必担心与其他线程之间的干扰。 4. **什么时候应该考虑使用 `ThreadLocal`?** - 当应用程序中有许多短生命周期的任务并且希望减少因频繁创建销毁临时对象带来的性能损耗时可以选择采用这种方式来进行优化处理。另外在某些情况下也可以利用它来传递上下文参数,例如事务传播级别或者用户身份认证令牌之类的信息贯穿整个业务流程之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值