ThreadLocal源码分析以及解决常见面试问题

参考:

https://www.cnblogs.com/ablejava/p/5914090.html 根本原因分析 


1,常规使用

    static final ThreadLocal<Long> longLocal = new ThreadLocal<>();
    static final ThreadLocal<String> stringLocal = new ThreadLocal<>();
    // 被调用的 入口
    public void testThreadLocal(String threadNameA, String threadNameB) {
        set();
        new Thread(new Runnable() {
            @Override
            public void run() {
                set();
                get();
            }
        }, threadNameA).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                set();
                get();
            }
        }, threadNameB).start();
        get();
    }
	// 统一,放入数据
    private void set() {
        longLocal.set(Thread.currentThread().getId());
        stringLocal.set(Thread.currentThread().getName());
    }
	// 统一,获取数据,并打印
    private void get() {
        long longNum = longLocal.get();
        String strName = stringLocal.get();
        LogUtil.v("longNum = " + longNum + ", strName = " + strName);
    }
打印结果:
V/xxx->MainActivity.get(L:57):: LogUtil -> longNum = 56015, strName = newThreadA
V/xxx->MainActivity.get(L:57):: LogUtil -> longNum = 56016, strName = newThreadB
V/xxx->MainActivity.get(L:57):: LogUtil -> longNum = 1, strName = main
总结:
    * 以上测试代码也是系统源码中使用ThreadLocal的方式
    * 以上测试结果,仅仅表明:ThreadLocal能够避免线程安全问题,因为多线程操作并没有产生冲突(多次尝试打印结果一样)

2,ThreadLocal的set、get方法

1) set方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); // 获取旧的ThreadLocalMap
        if (map != null)
            map.set(this, value); // 直接放置数据
        else
            createMap(t, value); // 创建新的ThreadLocalMap
    }
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
	
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
set的作用为:若当前线程,无ThreadLocalMap,则创建并放置数据;若当前线程,有ThreadLocalMap,则继续放入数据


2) get方法

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
	
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
2) get方法
get的作用为:若当前线程,有ThreadLocalMap,则获取其中的数据;若当前线程,无ThreadLocalMap,则获取默认初始化的数据
总结:
    * ThreadLocal放置和获取数据,都是以 this和value作为一对放入;因此,一个threadLocal,仅仅对应一个value
    * ThreadLocal<T> 中的泛型,和value的数据类型一致
    * ThreadLocal每次存放数据,都是放置到ThreadLocalMap中,而ThreadLocalMap是属于Thread的私有变量


3,ThreadLocalMap

    static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        private static final int INITIAL_CAPACITY = 16; // 初始容量
        private Entry[] table; // 具体存储的数据
	}
总结:
    * ThreadLocalMap和普通的map相同,是以数组作为实际的存储对象
    * ThreadLocalMap中数组对应的是,Entry(ThreadLocal、Value),并且key和value是弱引用;即:一旦某一方被回收,另一方是不会导致内存泄漏的


4,整体内存分析

1) 内存是以Thread为主,Thread持有ThreadLocalMap、ThreadLocalMap存放着(ThreadLocal<Value> - Value)这样的数组
因此,当多线程环境下,对应的引用关系如下图所示:

结论:多线程环境下,ThreadLocal是静态类型,因此多线程的key是相同的,但value是不同的;换句话说:value就是Thread的私有成员变量


5,依据以上分析解决常见的疑问

1) ThreadLocal 线程安全的原理
    线程安全的核心在于:多线程在使用共享数据时,造成的冲突;因此,对于私有变量而言,自然而然就没有线程安全的问题。
    而value每次通过Thread获取到的都是当前线程的私有变量,并没有多线程共享该数据,当然没有线程安全的问题

2) ThreadLocal 是否存在内存泄漏
    ThreadLocalMap的存储Entry{ThreadLocal - Value}关联方式为弱引用,因此当某个ThreadLocal置空,gc时,Value是能够被回收掉的;因此不存在内存泄漏问题

3) ThreadLocal 如何使用
    * ThreadLocal一定是共享的,最好是static final类型,原因:ThreadLocal<T>,可以通过T来固定Value为单一类型;并且static final类型,能够确保在内存中为一份且不可改变
    * Value值一定不能是static类型,若Value为static类型,ThreadLocal线程安全将失效

4) ThreadLocal 使用空间换时间,如何理解
    * 通过增加数组(存放引用)以及每个线程备份Value的方式,解决线程安全的问题



demo地址:

ThreadLocal 测试Activity







2) get方法
<think>好的,用户之前已经询问过Spring事务的实现原理,现在他进一步要求进行源码分析。这意味着他可能已经理解了基本概念,现在想深入底层机制,可能是为了面试准备或者解决实际问题。 首先,我需要确定用户对源码分析的深度。他是想了解整体流程还是某个具体部分的实现?比如事务管理器、AOP拦截、事务同步等。根据之前的回答,用户可能对动态代理和事务拦截流程感兴趣,所以需要聚焦在关键类和方法上。 接下来,用户可能遇到的实际问题是什么?比如事务不生效、传播行为不符合预期,或者是自调用问题。通过源码分析,可以解释这些问题的根本原因,比如自调用时AOP代理未生效,导致事务注解不被处理。 然后,我需要考虑如何组织源码分析的步骤。从配置开始,到代理创建,再到事务拦截器的工作流程,最后是事务管理器提交和回滚。这样结构清晰,用户能一步步跟进。 还要注意用户可能不熟悉的部分,比如TransactionSynchronizationManager的作用,或者事务传播行为的具体实现。需要用简单的例子和代码片段来解释,比如PROPAGATION_REQUIRED如何判断当前是否存在事务。 另外,用户可能对事务资源绑定到线程的机制感兴趣,这部分需要解释ThreadLocal的使用,以及连接获取和释放的时机,避免资源泄漏。 最后,需要提醒用户源码分析中的常见陷阱,比如自调用问题,以及事务和锁的关系,帮助他避免实际开发中的错误。同时,提供扩展点,比如如何自定义事务管理器或拦截器,满足高级需求。 总结来说,用户需要的是一个从配置到具体实现的详细源码解析,结合常见问题,帮助他深入理解Spring事务的内部工作机制,并解决实际问题。要确保步骤清晰,关键类和方法突出,同时用代码示例和流程说明来增强理解。</think>以下是Spring事务实现的核心源码分析,从配置加载到事务执行的全流程解析: --- ### 一、配置加载阶段(`@EnableTransactionManagement`) ```java // 源码位置:org.springframework.transaction.annotation.EnableTransactionManagement @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { // 关键点:导入TransactionManagementConfigurationSelector } ``` 1. **`TransactionManagementConfigurationSelector`** 选择使用JDK动态代理还是CGLIB代理,默认基于接口则用JDK,否则CGLIB。 2. **注册核心Bean** - `AutoProxyRegistrar`:负责注册`InfrastructureAdvisorAutoProxyCreator`(AOP代理创建器) - `ProxyTransactionManagementConfiguration`:定义事务相关的Advisor、Advice、Pointcut --- ### 二、代理对象生成(`InfrastructureAdvisorAutoProxyCreator`) ```java // 源码位置:org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { // 继承自AbstractAdvisorAutoProxyCreator,负责在Bean初始化后生成代理对象 } ``` 1. **Bean初始化后处理** 遍历所有Advisor(事务相关的`BeanFactoryTransactionAttributeSourceAdvisor`),匹配带有`@Transactional`的方法。 2. **代理创建逻辑** - 若目标类实现接口 → 使用JDK动态代理 - 若无接口 → 使用CGLIB代理 --- ### 三、事务拦截器(`TransactionInterceptor`) ```java // 源码位置:org.springframework.transaction.interceptor.TransactionInterceptor public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { // 核心事务执行逻辑 } } ``` **核心方法`invoke()`流程**: 1. **获取事务属性** ```java TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute( method, targetClass); ``` 解析`@Transactional`注解中的传播行为、隔离级别等属性。 2. **获取事务管理器** ```java PlatformTransactionManager tm = determineTransactionManager(txAttr); ``` 3. **执行事务逻辑** ```java // 处理事务传播行为(关键方法) TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal; try { // 执行业务方法 retVal = invocation.proceed(); } catch (Throwable ex) { // 根据异常决定回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // 提交事务 commitTransactionAfterReturning(txInfo); return retVal; ``` --- ### 四、事务管理器核心逻辑(以`DataSourceTransactionManager`为例) ```java // 源码位置:org.springframework.jdbc.datasource.DataSourceTransactionManager public class DataSourceTransactionManager extends AbstractPlatformTransactionManager { // 关键方法:doBegin() protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; Connection con = null; try { // 从DataSource获取连接,并绑定到当前线程 con = obtainDataSource().getConnection(); txObject.setConnectionHolder(new ConnectionHolder(con), true); // 设置事务隔离级别、只读等属性 prepareConnectionForTransaction(con, definition); // 绑定到TransactionSynchronizationManager TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()); } // ...其他逻辑 } } ``` **关键点**: 1. **连接绑定**:通过`TransactionSynchronizationManager`将数据库连接绑定到当前线程。 2. **事务同步**:确保同一事务内的多个操作使用同一个连接。 --- ### 五、事务传播行为实现(`AbstractPlatformTransactionManager`) ```java // 源码位置:org.springframework.transaction.support.AbstractPlatformTransactionManager private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) { // 处理PROPAGATION_NEVER:不允许存在事务,直接抛异常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException(...); } // 处理PROPAGATION_NOT_SUPPORTED:挂起当前事务 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { Object suspendedResources = suspend(transaction); // ...创建新事务状态 } // 处理PROPAGATION_REQUIRES_NEW:挂起当前事务并创建新事务 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { SuspendedResourcesHolder suspendedResources = suspend(transaction); try { return startTransaction(definition, transaction, debugEnabled, suspendedResources); } catch (RuntimeException | Error beginEx) { resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } } // ...其他传播行为处理 } ``` --- ### 六、事务提交与回滚(`AbstractPlatformTransactionManager`) ```java // 提交事务 protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null) { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } // 回滚事务 protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } else { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } } ``` --- ### 七、典型问题源码解析(自调用失效) **根本原因**:自调用时直接调用`this.methodB()`,未经过代理对象。 **源码验证**: 在`TransactionInterceptor.invoke()`中,只有通过代理对象调用才会进入拦截逻辑: ```java // 代理对象调用链路:Proxy → MethodInterceptor → 目标方法 // 自调用直接进入目标类方法,绕过代理 ``` --- ### 总结 Spring事务源码核心流程: **配置加载 → 代理生成 → 事务拦截 → 传播行为处理 → 连接绑定 → 提交/回滚** 关键类: - `InfrastructureAdvisorAutoProxyCreator`(代理生成) - `TransactionInterceptor`(事务拦截) - `DataSourceTransactionManager`(事务管理) - `TransactionSynchronizationManager`(资源同步)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值