在介绍ThreadLocal之前,先要说明一下java中的不同引用,这既是我们介绍ThreadLocal的必备知识,也是面试的经典问题
1 java的引用类型有哪几种?
1.强引用:如果一个对象具有强引用,例如,object o = new object()它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象
用途:大多数情况下,我们使用的都是强引用
2.软引用:Softreference<byte >m=new softreference<>(new byte[1024*1024*10])
注意此时m是强引用,数组中的每一个指向具体字节的引用为软引用不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
用途:非常适合缓存使用
3 弱引用(面试高频·)
WeakReference m = new WeakReference(new M());//**弱引用,注意,m仍然是强引用,第一个new出来的指向的引用是弱引用**
4 虚引用(实际开发中用的很少,面试问的也很少)
PhantomReference<M> phantomReference = new PhantomReference<>(newM(),QUEUE);
如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。凡是虚引用指向的对象,回收的时候都会放到一个队列QUEUE
里。然后再对queue进行回收
用途:经常用来管理直接内存,java的nio和netty就这样使用。jvm工作在用户态,很多网络io都在os态,jvm如果要访问这些数据,需要从os态复制一份到用户态,然后修改它。所以后来jvm有了directbuffer,指针直接指向os态的内存,对内存直接操作。
2 ThreadLocal
从ThreadLock的名字上来看,这是一个线程的局部变量。也就是说,只有当前线程可以访问。既然只有当前线程可以访问,那当然是线程安全的。
原理:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
观察Threadlocal的set方法,key为this,值为value。其中的key就是调用set方法的Threadlocal对象。而map是Thread类中的ThreadLocal.ThreadLocalMap threadLocals = null;
由于它是Threadlocal的局部变量,所以map的值是线程隔离,所以value的值也就是线程隔离的。
这个Map里的entry是weakreference的子类
static class Entry extends WeakReference<Threadlocal<?>>{
Object value;
Entry(ThreadLocal<?>k,Object v){
super(k);//调用了父类WeakReference的构造函数,所以这个key局势一个弱引用
value=v;}}
为什么entry使用弱引用?
1 若是强引用,既是tl=null,key仍然指向ThreadLocal,并且永远不会被访问到,GC也无法回收,造成内存泄漏
2 但是即使使用弱引用,仍然有可能内存泄漏,ThreadLocal被回收,key的值变为null,导致value永远不会被访问到,还是会造成内存泄漏,所以应该习惯性的remove掉。
ThreadLocal的应用
spring关于transition的处理
Mybatis关于分页的处理