Java并发编程-ThreadLocal

1.注意事项

  • 使用ThreadLocaL时要注意:为每个线程分配一个对象的工作并不是由ThreadLocal来完成的,而是需要在应用层面保证的。如果在应用层为每个线程都分配了同一个对象实例,那么ThreadLocal也不能保证线程安全。

2.实现原理

  • ThreadLocal的实现原理:分两步,第一步是从当前线程对象,拿到到ThreadLocalMap对象(是Thread对象的一个名为threadLocals的成员变量);第二步是根据ThreadLocalMap对象维护的映射关系,由当前ThreadLocal对象(作为key),得到value。(注意,ThreadLocalMap类并没有实现Map接口,但从功能上可以理解为一个Map)
    Java并发编程-ThreadLocal_第1张图片
    ThreadLocal(1).png-30.3kB

3.清理工作

  • 通过ThreadLocal的实现原理,我们可以发现,这些变量都是维护在Thread类内部的,这也就意味着只要线程不退出,对象的引用就一直存在。
  • 而当我们使用线程池时,就意味着当前线程未必会退出,这种情况下,如果我们将一些很大的对象设置到ThreadLocal中,就会使系统出现内存泄漏的可能(这个对象已经不再有用了,但却无法被回收)。
  • 清理ThreadLocal有两种方式:

1.使用ThreadLocal.remove()方法

  • 使用ThreadLocal.remove()方法移除变量,这就像我们习惯性地关闭数据库连接一样,如果确定不需要这个对象了,那么就应该告诉虚拟机,请把它回收掉,防止内存泄漏。

2.手动将ThreadLocal对象置为null

  • 手动将ThreadLocal对象置为null,例如threadLocal=null,那么这个ThreadLocal对应的所有线程的局部变量都有可能被回收。
  • 之所以可以这样,这是因为ThreadLocalMap的实现使用了弱引用(ThreadLocalMap非常类似于WeakHashMap)。弱引用就是比强引用弱得多的引用。Java虚拟机在垃圾回收时,如果发现弱引用,就会立即回收。ThreadLocalMap内部由一系列Entry构成,每一个Entry都是WeakReference
static class Entry extends WeakReference> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal k, Object v) {
        super(k);
        value = v;
    }
}
  • 因此,虽然这里使用ThreadLocal作为Map的key,但实际上,它并不真的持有ThreadLocal的引用。而当ThreadLocal的外部强引用被回收时,ThreadLocalMap中的key就会变成null。当系统进行ThreadLocalMap 清理 时(比如将新的变量加入表中,就会自动进行一次清理),就会自然将这些垃圾数据回收:
    Java并发编程-ThreadLocal_第2张图片
    ThreadLocal的回收机制.png-159.6kB

END

参考资料:《实战Java高并发程序设计》

你可能感兴趣的:(Java并发编程-ThreadLocal)