ThreadLocal源码解读内存泄漏分析

本文深入解析了JDK1.2引入的ThreadLocal工具类,阐述其在多线程程序中的作用,如对象跨层传递、线程间数据隔离、事务操作等,并通过示例代码展示如何使用。同时,分析了ThreadLocal的get、set、remove方法源码,提醒开发者注意内存泄漏问题。

早在JDK1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。但是ThreadLocal并不是一个线程,他是一个线程变量。意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。伴随整个线程生命周期存在,可以作为线程执行,对象跨层,父子线程通信,线程追踪的标记。

ThreadLocal作用

1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。

2、线程间数据隔离

3、进行事务操作,用于存储线程事务信息。

4、数据库连接,Session会话管理。

ThreadLocal怎么用

public class ThreadLocalTest {

    static ThreadLocal<String> local = new ThreadLocal<>();

    static void print(String str) {
        //打印当前线程中本地内存中本地变量的值
        System.out.println(str + " :" + local.get());
        //清除本地内存中的本地变量
        local.remove();
    }

    public static void main(String[] args) {
        Thread t1  = new Thread(new Runnable() {
            @Override
            public void run() {
                //设置线程1中本地变量的值
            	local.set("local1");
                //调用打印方法
                print("thread1");
                //打印本地变量
                System.out.println("after remove : " + local.get());
            }
        });

        Thread t2  = new Thread(new Runnable() {
            @Override
            public void run() {
                //设置线程1中本地变量的值
            	local.set("local2");
                //调用打印方法
                print("thread2");
                //打印本地变量
                System.out.println("after remove : " + local.get());
            }
        });

        t1.start();
        t2.start();
    }
}

ThreadLocal源码分析
重点是get,set,remove方法
get方法源码

public Object get()
    {
        Thread thread = Thread.currentThread();
        ThreadLocalMap threadlocalmap = getMap(thread);
        if(threadlocalmap != null)
        {
            ThreadLocalMap.Entry entry = threadlocalmap.getEntry(this);
            if(entry != null)
                return entry.value;
        }
        return setInitialValue();
    }

set方法源码

private void set(ThreadLocal threadlocal, Object obj)
        {
            Entry aentry[] = table;
            int i = aentry.length;
            int j = threadlocal.threadLocalHashCode & i - 1;
            for(Entry entry = aentry[j]; entry != null; entry = aentry[j = nextIndex(j, i)])
            {
                ThreadLocal threadlocal1 = (ThreadLocal)entry.get();
                if(threadlocal1 == threadlocal)
                {
                    entry.value = obj;
                    return;
                }
                if(threadlocal1 == null)
                {
                    replaceStaleEntry(threadlocal, obj, j);
                    return;
                }
            }

            aentry[j] = new Entry(threadlocal, obj);
            int k = ++size;
            if(!cleanSomeSlots(j, k) && k >= threshold)
                rehash();
        }

remove方法源码

 private void remove(ThreadLocal threadlocal)
        {
            Entry aentry[] = table;
            int i = aentry.length;
            int j = threadlocal.threadLocalHashCode & i - 1;
            for(Entry entry = aentry[j]; entry != null; entry = aentry[j = nextIndex(j, i)])
                if(entry.get() == threadlocal)
                {
                    entry.clear();
                    expungeStaleEntry(j);
                    return;
                }

        }

ThreadLocal内存泄漏问题
使用set方法移除key,但是value依然在并不会被垃圾回收器回收,value会一直持续到线程结束才会被回收,这就存在内存泄漏的可能性。可以使用remove移除value来避免内存泄漏。

ThreadLocal是Java中的一个线程本地变量,它提供了一种线程安全的方式来存储每个线程的局部变量。ThreadLocal的实现原理是在每个线程中创建一个独立的副本,每个线程都可以访问自己的副本,从而避免了线程安全问题ThreadLocal的内部结构主要包括ThreadLocal类和ThreadLocalMap类。ThreadLocal类是一个泛型类,用于存储线程本地变量的值。ThreadLocalMap类是一个自定义的哈希表,用于存储每个线程的ThreadLocal变量副本。 在jdk8之前,ThreadLocalMap是通过自定义的Entry数组来实现的,每个Entry包含一个ThreadLocal对象和对应的值。在jdk8之后,ThreadLocalMap的实现方式发生了变化,它使用了类似于HashMap的Node数组来存储Entry,从而提高了性能。 ThreadLocal内存泄漏问题是指在使用ThreadLocal时,由于没有及时清理ThreadLocal变量,导致线程结束后ThreadLocal变量没有被回收,从而导致内存泄漏。解决ThreadLocal内存泄漏问题的方法是在使用完ThreadLocal变量后,调用remove()方法将其从ThreadLocalMap中删除。 下面是一个简单的示例,演示了如何使用ThreadLocal来存储线程本地变量: ```java public class ThreadLocalDemo { private static final ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { Thread t1 = new Thread(() -> { threadLocal.set("Hello from thread 1"); System.out.println(threadLocal.get()); }); Thread t2 = new Thread(() -> { threadLocal.set("Hello from thread 2"); System.out.println(threadLocal.get()); }); t1.start(); t2.start(); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值