Java并发--ThreadLocal

ThreadLocal 用于存储线程私有的对象。

查看 Thread 类的源码可以发现,每个 Thread 对象中都会有一个 ThreadLocalMap 的属性,它是一个 HashMap 结构, key 是 ThreadLoacl 对象, value 是该 ThreadLocal 存储的 Object。

线程初始时,ThreadLocalMap 是空的,当我们需要为线程设置它的私有对象时,可以新建一个 ThreadLocal 对象,像这样:

ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();

它的主要方法有:

public T get() { }  
public void set(T value) { }  
public void remove() { }  
protected T initialValue() { } 

然后可以通过 set 方法放进去一个对象,可以通过 get 方法获取对象。

我们来看一张图就清晰了。

ThreadLocal 和它的 Object 就是存在了该线程的 ThreadLocalMap 中,所以很明显是线程私有的。

如果线程挂了,ThreadLocalMap 失去引用,就会被回收掉。

  • 弱引用问题

    ThreadLocalMap 中用到了弱引用,ThreadLocalMap 的 Entry 中 key 是 ThrealLocal 对象, value 是 ThrealLocal 对象所对应的 Object。如果出现这样的情况:程序中的 ThreadLocal 对象失去了强引用,但是 key 仍然持有对它的引用,如果这个引用是强引用,ThreadLocal 将永远不会被回收。因此这里设计者把 key 对 ThreadLocal 的引用设置为了弱引用。(个人认为这里是防止了ThreadLoacl对象无法回收导致的内存泄露,下小节讲的是Object对象产生的内存泄露)

  • 内存泄露问题

    如果线程一直活着,但是 ThreadLocal 因为一些操作导致失去了强引用,那么它就会被回收。那么将导致 ThreadLocalMap 中存在 <null, Object> 的键值对,即内存泄露了。

    所以在使用完 ThreadLocal 后,应该调用 remove 主动移除ThreadLocalMap 中的键值对。

  • 使用注意

    一般我们把 ThreadLocal 定义为 static(这是JDK的推荐),因为如果ThreadLocal 是实例属性,那么在线程中每创建一个这个类的实例,就也会新建一个 <ThreadLocal, Object>, 对于 Object 而言是存在冗余的,因此也造成了一定的浪费。

*关于内存泄露这块感觉理解还不是很深,主要是没有结合实际生产案例。

原文地址:https://www.cnblogs.com/cpcpp/p/15212445.html