ThreadLocal的原理和内存泄露

ThreadLocal的原理和内存泄露

ThreadLocal的用法

ThreadLocal可以保证一个线程共享一个变量,例如

static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args){
	Thread thread1 = new Thread(()->{
		threadLocal.set("hello");//线程1设值
	});
	
	Thread thread2 = new Thread(()->{
		System.out.println(threadLocal.get());//线程2取值
	});
	
	thread1.start();
	try {
		thread1.join();//保证线程1完成了设值
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	thread2.start();//线程2取值,输出结果null
}

可以看出两个线程不共享资源,这是如何实现的呢?

原理

每个线程里有个map,k和v的映射关系是:通过threadlocal,映射到value,也就是说。threadlocal.set执行的步骤是:

  1. 获取当前线程实例thread
  2. 从thread中获取threadlocalmap
  3. 把threadlocal实例->value的映射关系放进threadlocalmap

取值的步骤是:

  1. 获取当前线程实例thread
  2. 从thread中获取threadlocalmap
  3. 从threadlocalmap中根据threadlocal获取value

内存泄露

为什么会有内存泄露的可能呢

首先啥是内存泄露?就是内存中有一个对象,无法被回收。

如果我们执行这个命令希望不再使用threadlocal:

threadlocal=null;

我们预期的结果是这个变量应该要被回收。但是threadlocal自打它出生开始,就有其他的变量持有这个引用——也就是我们刚刚说的threadlocalmap,这个存在于线程内部的变量,一直持有这个threadlocal,通过threadlocal = null无法把全部的引用清空,所以直到整个线程结束之前,无法被垃圾回收。

java源码巧妙地解决了这个问题,有一种引用形式是弱引用:

弱引用:下次垃圾回收就给回收了

threadlocalmap对threadlocal的引用方式就是弱引用。threadlocal的对象的引用就只有threadlocal和threadlocalmap内部的引用,如果执行了threadlocal=null之后threadlocal的对象只剩一个弱引用,在下次垃圾回收的时候这个对象就会被清理了。

隐藏的问题

正如刚才所说,是通过弱引用对threadlocal进行持有的,代码如下:

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

Entry是个弱引用持有了key,也就是threadlocal,threadlocal对象threadlocal=null之后就会被回收,但是value这个对象作为Entry的成员变量一直被Entry对象持有,并且由于threadlocal对象已经被回收了,无法通过这个key来找到这个value对象,所以同样在线程结束之前无法回收value的值。

解决办法

如果有一个threadlocal不用了,要使用remove方法。

threadlocal.remove();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值