ThreadLocal

1、概念

java.lang.ThreadLocal,提供了线程局部变量,这些变量不同于它们的普通对应物。ThreadLocal实例通常是类中的private static 字段,并且希望将状态与某一个线程(例如事物ID),相关联
它就是一个容器,用于存放线程的局部变量
它产生的原因,是用来解决多线程并发问题而设计的

ThreadLocal在开源框架中都有运用,它有一个内部静态类static class ThreadLocalMap {} ,它的key是当前线程,而value就是我们想保证数据安全一致的某个对象
ThreadLocal就像是超市里的存包的柜子,每个线程只有拿着自己的key,才能得到对应的value

当在一个类中使用了static的成员变量的时候,如果需要它是线程安全的,也就是说多个线程需要独享自己的static的成员变量,那就使用ThreadLocal

一般是通过ThreadLocal来存放java.sql.Connection,来达到事务控制的能力,因为事务控制的关键就是不同的事务,同一个Connection对象

2、常用方法

⑴ public void set(T value) {}
将ThreadLocal的当前线程中的value设置为指定值

⑵ public T get() {}
获取ThreadLocal的当前线程中的value

⑶ public void remove() {}
移除ThreadLocal的当前线程中的value

3、示例【获取和释放Connection对象】

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

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JdbcUtils {
    private static DataSource dataSource;
    private static ThreadLocal<Connection> threadLocal;

    static {
        // 创建C3P0连接池对象【修改为<named-config name="???">的name属性值】
        dataSource = new ComboPooledDataSource("???");
        threadLocal = new ThreadLocal<Connection>();
    }

    public static Connection getConnection() {
        Connection connection = null;

        // 从ThreadLocal的当前线程中获取Connection对象
        connection = threadLocal.get();

        // 如果ThreadLocal的当前线程中没有Connection对象
        if (null == connection) {
            try {
                // 从连接池中获取连接
                connection = dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 放到ThreadLocal的当前线程中
                threadLocal.set(connection);
            }
        }

        return connection;
    }

    public static void releaseConnection(Connection connection) {
        if (null != connection) {
            try {
                // 放回到连接池中
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 将ThreadLocal的当前线程中的Connection移除
                threadLocal.remove();
            }
        }
    }

}
### ThreadLocal 的基本概念 `ThreadLocal` 是 Java 中的一个类,用于创建线程本地变量 (thread-local variables)[^1]。这些变量的特点在于每个线程都有自己的独立副本,因此即使多个线程访问同一个 `ThreadLocal` 实例,它们也不会相互干扰。 #### 创建和初始化 ThreadLocal 变量 可以通过以下方式来定义并初始化一个 `ThreadLocal` 对象: ```java ThreadLocal<Integer> threadLocalVariable = new ThreadLocal<>(); // 或者通过提供初始值的方式 ThreadLocal<Integer> initializedThreadLocal = ThreadLocal.withInitial(() -> 0); ``` 上述代码展示了两种不同的方法来实例化 `ThreadLocal` 对象。第一种方式未指定默认值,在首次调用前会返回 `null`;第二种则提供了 lambda 表达式作为其初始值设定逻辑[^2]。 ### 使用场景分析 `ThreadLocal` 常被用来处理多线程环境下的数据隔离问题。例如数据库连接、Session 管理或者事务控制等方面都可以利用它实现每条线程拥有自己单独的状态信息而不影响其他线程的工作状态[^3]。 #### 示例程序展示如何应用 ThreadLocal 来保存当前用户的登录名 ```java public class UserContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public static void setUserName(String userName){ System.out.println(Thread.currentThread().getName() + ": Setting user name - "+userName); contextHolder.set(userName); } public static String getUserName(){ return contextHolder.get(); } public static void remove(){ contextHolder.remove(); // 清除资源防止内存泄漏 } } class Task implements Runnable{ private String username; public Task(String username){ this.username=username; } @Override public void run() { try { UserContextHolder.setUserName(username); // Simulate some processing time. Thread.sleep(1000L); System.out.println(Thread.currentThread().getName()+": Current UserName is "+UserContextHolder.getUserName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { UserContextHolder.remove(); } } } ``` 在这个例子中,我们模拟了一个简单的任务执行过程,并且使用了 `ThreadLocal` 存储用户名以便于后续操作能够获取到正确的用户身份标识符[^4]。 ### 最佳实践建议 - **及时清理资源**:当不再需要某个特定的 `ThreadLocal` 数据时应该显式地调用 `.remove()` 方法释放关联的对象引用以防潜在的内存泄露风险。 - **避免存储大对象**:由于每个线程都会持有属于它的那份拷贝,如果存放大体积的数据结构可能会造成不必要的开销甚至 OOM 错误。 - **合理设置初值函数**:对于那些可能频繁读取却很少修改的情况可以考虑采用懒加载模式减少性能损耗[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值