ThreadLocal:的面试

ThreadLocal:

       为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。

  当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

  从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

void set(Object value)设置当前线程的线程局部变量的值。
public Object get()该方法返回当前线程所对应的线程局部变量。
public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
  值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,
该类的类名已经变为ThreadLocal<T>。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。   ThreadLocal是如何做到为每一个线程维护变量的副本的呢?
其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。

  

ThreadLocal源码源码的人都知道,ThreadLocal的设计的确巧妙,但是它也有一个缺陷:

可能会引起内存泄漏;

ThreadLocalMap中key维护着一个weakReference,它在下次GC之前会被清理,如果Value仍然保持着外部的强引用,该ThreadLocal没有再进行set,get或者remove操作,时间长了就可能导致OutOfMemoryError .

lucene中的类CloseableThreadLocal对ThreadLocal做了处理,优化了其缺陷.学习一下:
当执行CloseableThreadLocal.set(T)时,内部其实只是把值赋给内部的ThreadLocal对象,即执行ThreadLocal.set(new WeakReference(T)),将T包装成弱引用对象,目的就是当内存不足时,jvm可以回收此对象.

这样引入一个新的问题:当前线程还存活着的时候,因为内存不足而回收了弱引用对象,这样会在下次调用get()时取不到值返回null,这是不可接受的.所以CloseableThreadLocal在内部还创建了一个私有的Map,WeakHashMap<Thread, T>,当线程只要存活时,则T就至少有一个引用存在,所以不会被提前回收。同时要注意另一个问题,要对WeakHashMap的操作使用synchronized做同步.
文章转载:https://blog.csdn.net/qunqunstyle99/article/details/94717256

线程池中的线程使用threadlocal会出现什么问题?

 线程池中的线程在任务执行完成后会被复用,所以在线程执行完成时,要对 ThreadLocal 进行清理(清除掉与本线程相关联的 value 对象)。不然,被复用的线程去执行新的任务时会使用被上一个线程操作过的 value 对象,从而产生不符合预期的结果。

原文地址:https://www.cnblogs.com/fengli9998/p/11531649.html