ThreadLocal

本文深入解析了ThreadLocal的工作原理,展示了其如何通过内部Map实现线程局部变量的存储与检索,有效避免了线程间的数据冲突。并详细介绍了ThreadLocal在数据库连接管理及Struts2框架中的具体应用案例。

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

ThreadLocal提供了线程局部变量,可以视为内部通过一个Map(实际是内部类ThreadLocalMap)存取数据,存取数据只在同一线程有效。
下面是该类的简单模拟,实际比这复杂:

public class ThreadLocal<T>{
private Map<Runnable,T> map = new HashMap<Runnable,T>();
//把传入的参数绑定到当前线程上
public void set(T t){
    map.put(Thread.currentThread(),t);  
}
//从当前线程上删除对象
public void remove(){
    map.remove(Thread.currentThread());
}
//获取当前线程上绑定的对象
public T get(){
    return map.get(Thread.currentThread()); 
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

应用:
1、管理Connection,控制事物开启关闭

import java.sql.Connection;
import java.sql.SQLException;

/**
 * 封装事物相关方法,确保dao层中使用的Connection相同
 */
public class TransactionManager {
    //
    private static ThreadLocal<Connection> tLocal=new ThreadLocal<>();
    /**
     * 从线程中获取连接
     * @return
     */
    public static Connection getConnection(){
        Connection conn = tLocal.get();
        if(conn==null){
            conn=DBCPUtil.getConnection();
            tLocal.set(conn);
        }
        return conn;
    }
    /**
     * 开启事物
     */
    public static void startTransaction(){
        try {
            Connection conn = getConnection();
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 回退
     */
    public static void rollback(){
        try {
            Connection conn = getConnection();
            conn.rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 提交
     */
    public static void commit(){
        try {
            Connection conn = getConnection();
            conn.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 连接回到连接池,线程局部变量清空
     */
    public static void release(){
        try {
            Connection conn = getConnection();
            conn.close();
            tLocal.remove();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

2、在struts2框架中,ActionContext就是通过此类控制的

static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
  • 1

一个ThreadLocal的应用例子:

public class SourceUtil{
    private static ThreadLocal<Map<String,Object>> tl=new ThreadLocal<Map<String,Object>>(){
        @Override
        protected synchronized Map<String,Object> initialValue(){
            return new HashMap<String,Object>();
        }
    };

    public static Map<String,Object> getSource(){
        return tl.get();
    }

    public static void putSource(Map<String,Object> user){
        tl.set(user);
    }

    public static void put(String key,Object value){
        tl.get().put(key,value);
    }

    public static Object get(String key){
        return tl.get().get(key);
    }

    public static void clear(){
        tl.remove();
    }
}
### ThreadLocal的使用场景 ThreadLocal适用于需要在多线程环境中为每个线程独立存储和操作数据的场景。常见的使用场景包括: - **线程上下文传递**:例如在Web应用中,每个请求由一个线程处理,可以通过ThreadLocal保存请求相关的上下文信息,如用户身份、事务对象等,避免频繁传递参数[^2]。 - **线程安全的变量管理**:当多个线程需要访问某个变量,但每个线程对该变量的操作互不影响时,可以使用ThreadLocal来避免同步开销[^3]。 - **资源持有**:某些资源(如数据库连接、Session等)需要在线程内部共享,但不希望多个线程之间共享,ThreadLocal可以很好地满足这种需求[^1]。 ### ThreadLocal的实现原理 ThreadLocal的实现机制主要依赖于线程内部的ThreadLocalMap结构: - 每个线程(Thread类)内部维护一个ThreadLocalMap对象,该Map的键为ThreadLocal实例,值为存储的变量副本[^4]。 - ThreadLocalMap使用**弱引用(WeakReference)**作为键,以避免内存泄漏。当ThreadLocal对象不再被外部引用时,垃圾回收器可以正常回收该对象,但需要注意Map中对应的值仍需手动清理[^5]。 - 每个ThreadLocal实例都有一个唯一的哈希码(threadLocalHashCode),用于在ThreadLocalMap中快速定位存储位置[^5]。 通过这种机制,每个线程访问同一个ThreadLocal变量时,实际上访问的是各自线程独立的变量副本,从而实现了线程安全。 ### 示例代码 以下是一个简单的ThreadLocal使用示例: ```java public class ThreadLocalExample { // 定义一个ThreadLocal变量 private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { // 创建多个线程进行测试 for (int i = 0; i < 3; i++) { new Thread(() -> { // 设置线程本地变量 threadLocal.set((int) (Math.random() * 100)); // 获取线程本地变量 System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get()); }).start(); } } } ``` 在这个例子中,每个线程都设置了不同的整数值,彼此之间互不影响。 ### 总结 ThreadLocal通过为每个线程提供独立的变量副本,解决了线程安全问题,并在某些场景下提升了性能。其核心在于每个线程内部维护的ThreadLocalMap结构,以及基于弱引用的键值对管理机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值