ThreadLocal详解

1.Threadlocal是什么?

ThreadLocal提供了线程的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离。

2.目的是什么?

ThreadLocal设计的目的就是为了能够在当前线程中有属于自己的变量,并不是为了解决并发或者共享变量的问题。很多同学在初学的时候会误解

3.作用?

举个例子:像我们学习jdbc的时候,连接数据库。数据库连接池的连接怎么管理呢??我们交由ThreadLocal来进行管理。为什么交给它来管理呢??ThreadLocal能够实现当前线程的操作都是用同一个Connection,保证了事务

4.用法?

主要方法如下:都依赖于ThreadLocal.ThreadLocalMap内部类。

//获取值
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;
}

//设置值
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

//获取线程关联的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

//创建ThreadLocalMap
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocal.ThreadLocalMap内部类

ThreadLocal.ThreadLocalMap内部类,维护着每个线程自己的多个ThreadLocal变量, key为当前的threadLocal实例(ThreadLocal本身不存值,只是引用),value为设置的值 (值存放在ThreadLocal.ThreadLocalMap.Entry实例中)。关键定义如下:

static class ThreadLocalMap {
		//存储数据的数组
  	private Entry[] table;
		//获取Entry,key的类型为ThreadLocal
    private Entry getEntry(ThreadLocal<?> key) {
              int i = key.threadLocalHashCode & (table.length - 1);
              Entry e = table[i];
              if (e != null && e.get() == key)
                  return e;
              else
                  return getEntryAfterMiss(key, i, e);
    }
  }

ThreadLocal.ThreadLocalMap.Entry内部类

ThreadLocal.ThreadLocalMap.Entry内部类,是存储数据的实际数据结构,继承WeakReference,因此是个弱引用,当虚拟机垃圾回收时,无论内存是否足够,都会被回收。

static class Entry extends WeakReference<ThreadLocal<?>> {
    / The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

5.原理?

  • 1.每个Thread维护着一个ThreadLocalMap的引用

  • 2.ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储

  • 3.调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象

  • 4.调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象

  • 5.ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。

6.注意点:

使用ThreadLocal要注意内存泄露,使用完后,要主动调用remove()方法。原因:

  • Entry的key是个WeakReference弱引用的ThreadLocal对象,会被垃圾回收,回收后,key会变为null,但value还存在,而又无法通过已经变为null的key索引到value,因此value所在内存便无法使用,又无法回收,导致内存泄露。
  • ThreadLocalMap(即位于Thread中的变量)threadLocals本身的生命周期与线程一致,即使ThreadLocal本身弱引用已经回收,但value还存在于ThreadLocalMap中的Entry中,导致内存泄露。

ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。

想要避免内存泄露就要手动remove()掉!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值