1.什么是ThreadLocal?

ThreadLocal是Java为Thread提供的本地存储机制,可以在Thread通过ThreadLocal(set方法)缓存数据,缓存之后可以在线程执行时的任意执行点、任意时间点获取(get方法)缓存的数据。

Thread的ThreadLocal本地存储内存区相互隔离,并不共享;但是如果ThreadLocal关联的缓存数据为堆对象时,不同的Thread的ThreadLocal关联到同一个堆对象,这个时候如果有修改操作不是线程安全的。

2.ThreadLocal实现的原理

Thread内部有一个类型为ThreadLocalMap的threadLocals字段,用于存储线程的ThreadLocal数据。每个Thread线程对象都存在一个ThreadLocalMap。

ThreadLocalMap本质上是一个哈希表,采用开放地址法实现,在使用过程中会出现Entry数组扩缩容。

ThreadLocalMap是ThreadLocal的内部类,不能直接使用,只能使用ThreadLocal的api方法。

public class ThreadLocal<T> {
    public T get() {
        #获取当前线程Thread的ThreadLocal
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        // 其他操作
    }

    ThreadLocalMap getMap(Thread t) {    
        return t.threadLocals; 
    }
}

3.使用ThreadLocal的注意事项

static class Entry extends WeakReference<ThreadLocal<?>>

ThreadLocalMap的Entry为弱引用,方便JVM能自动回收ThreadLocal对象,在方法执行完成后,当ThreadLocal对象不存在强引用时,JVM在接下来出现的第一次gc时会自动回收ThreadLocal对象。

虽然通过弱引用Entry.k指向的ThreadLocal对象能自动回收,但是Entry.value指向的数据对象并不会自动回收,当Entry.k为null时,后边如果调用了这个ThreadLocal的get,set方法时会触发移除Entry对象。

Thread保持执行时,Entry对象被Thread强引用,Entry.value也会强引用数据对象,也就是说只要Entry对象不从ThreadLocalMap中移除,Entry对象和Entry.valude指向的数据对象就会被Thread强引用,都是到根可达的,就不会被JVM回收。

Thread执行退出后相关的ThreadLocalMap,ThreadLocal和数据对象都会被JVM回收;线程池中的线程生命周期同JVM一样,ThreadLocal使用不当会导致内存泄露。

当ThreadLocal缓存数据不在使用时一定要使用ThreadLocal.remove从ThreadLocalMap中移除,让JVM能回收这些内存。

java thread 数据请求 java中的threadlocal_强引用

 

4.ThreadLocal的使用场景

经典的使用场景是连接管理,一个线程持有一个连接,不需要通过参数传递就能在不同的方法中使用这个连接,不同的线程使用不同的连接,不需要加锁同步,提高并发性能。