Threadlocal的使用以及实现原理总结

Threadlocal总结

  • ThreadLocal 并不解决线程间共享数据的问题
  • ThreadLocal 通过隐式的在不同线程内创建独立实例副本避免了实例线程安全的问题
  • 每个线程持有一个 Map(Map的key为ThreadLocal对象本身,值为ThreadLocal对象实际所包含的对象) 并维护了 ThreadLocal 对象与具体实例的映射,该 Map 由于只被持有它的线程访问,故不存在线程安全以及锁的问题
  • ThreadLocalMap 的 Entry 对 ThreadLocal 的引用为弱引用,避免了 ThreadLocal 对象无法被回收的问题
  • ThreadLocalMap 的 set 方法通过调用 replaceStaleEntry 方法回收键为 null 的 Entry 对象的值(即为具体实例)以及 Entry 对象本身从而防止内存泄漏
  • ThreadLocal 适用于变量在线程间隔离且在方法间共享的场景

Threadlocal 结构以及实现

  • 每个Thread对象有一个ThreadlocalMap属性,ThreadlocalMap类始于Map的k-v结构。key是threadlocal对象,value就是threadlocal对象指向的实际对象。值得一提的是ThreadlocalMap对于hash冲突采用的是线性探测法来解决hash冲突的,不同于hashMap的拉链法。
  • threadlocal的set方法
  • threadlocal的get方法
  • 很明显的看出每次执行threadlocal对象的get和set方法的时候就是先取出当前的线程t,然后再取出这个线程对应的ThreadlocalMap,再通过threadlocal对象作为key取出对应entry在取出entry的value。
  • 需要注意的是注意的是ThreadlocalMap是threadlocal的内部类,entry又是ThreadlocalMap的内部类
  • entry的key是弱引用从他的构造函数可以看出,为什么是弱引用呢,因为当threadlocal对象不在使用的时候将其置位null,但是这个时候entry的key还是指向的threadlocal对象,如果这个时候是强引用就会导致threadlocal对象没办法回收会造成内存泄漏,所以改成弱引用的话当只有一个弱引用的entry的key指向threadlocal对象的时候Threadlocal对象在垃圾回收的时候就会被回收掉。

关于ThreadLocal的内存泄露问题

  • 虽然Entry的Key对ThreadLocal对象是一个弱引用,保证了当除了Entry以外的引用指向ThreadLocal对象可以保证ThreadLocal对象被回收,但是对于Entry中的value的回收却没有像这样解决

  • 对于Entry中的Value,因为是跟当前线程绑定,只要线程没有被回收那么这个Value是不会被回收的,特别是在线程池的情况下线程被复用导致Value一直不回被回收。如果线程执行完任务后马上被回收就不会有这个问题

  • 关于这个value的内存泄露问题ThreadLocal也有自己的解决办法,在ThreadLocalMap进行Set和get操作的时候,因为采用的是开放地址法解决hash冲突,有时候会因为在get和set的过程中会遍历一部分ThreadLocalMap中的entry数组,当发现key为null的entry的时候会主动清理掉这个无效的entry。

  • 还有就是当我们使用完一个ThreadLocal对象时,主动执行remove方法来清理内存。

  • 参考博客:www.jasongj.com/java/thread…

你可能感兴趣的:(java)