本文共 5469 字,大约阅读时间需要 18 分钟。
工作中用到了ThreadLocal,觉得非常巧妙好用,顾总结下
工作中就是利用了ThreadLocal省去了频繁的传递参数。
先写一个工具类
public class VersionHodler { private static ThreadLocal<docVersion> docVersionMap = new ThreadLocal<>(); public static void setVersionMap(docVersion versionMap){ docVersionMap.set(versionMap); } public static docVersion getVersionMap(){ return docVersionMap.get(); } //用完清除避免内存泄漏 public static void clear(){ topicDocVersionMap.remove(); } //传递一个内部类作为介质 public static class DocVersion{ private Integer finishStatus; private Integer topicVersion; public Integer getFinishStatus() { return finishStatus; } public void setFinishStatus(Integer finishStatus) { this.finishStatus = finishStatus; } public Integer getTopicVersion() { return topicVersion; } public void setTopicVersion(Integer topicVersion) { this.topicVersion = topicVersion; } }}
使用时 ,先在需要传递参数的业务代码那里设值:
//这里省略业务代码,如某个controller调用了n多逻辑,controller-->service1-->service2-->dao-->某save方法try { VersionHodler.DocVersion docVersion = new VersionHodler.docVersion(); docVersion.setFinishStatus(xxx.getFinishStatus()); docVersion.setTopicVersion(xxx.getTopicVersion()); VersionHodler.setVersionMap(docVersion); } finally { VersionHodler.clear(); }
最后需要在使用这个变量的地方,如某save方法中:
//先把变量取出来VersionHodler.DocVersion docVersion = VersionHodler.getVersionMap();//执行代码
最后,好处应该可以看到了controller-->service1-->service2-->dao-->某save方法
当中不需要传递参数,直接在需要取参数的地方就能取到,避免频繁的传递参数,也没有使用到锁机制。如果某场景下代码量已经很多 ,后期由于某个需求需要添加一个参数,那么这个改动量是非常大的。
使用完ThreadLocal后,执行remove操作,避免出现内存溢出情况。
为什么会内存溢出呢?看源码(jdk1.8)~
1.首先看ThreadLocal里面保存的是什么值。看set方法。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
首先获取到了当前线程t,然后调用getMap获取ThreadLocalMap,如果map存在,则将当前线程对象t作为key,要存储的对象作为value存到map里面去。如果该Map不存在,则初始化一个。
2.再看ThreadLocalMap是什么
static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } //... 省略}
ThreadLocalMap其实就是ThreadLocal的一个静态内部类,里面定义了一个Entry来保存数据,而且还是继承的弱引用。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。
还有一个getMap
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
调用当期线程t,返回当前线程t中的成员变量threadLocals。而threadLocals其实就是ThreadLocalMap。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
首先获取当前线程,然后调用getMap方法获取一个ThreadLocalMap,如果map不为null,那就使用当前线程作为ThreadLocalMap的Entry的键,然后值就作为相应的的值,如果没有那就设置一个初始值。
不会回收
它。当内存空间不足,java虚拟机宁愿抛出OOM(OutOfMemory),使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。只有到JVM内存不足的时候才会调用垃圾回收期回收掉这个对象
。软引用和一个引用队列联合使用,如果软引用所引用的对象被回收之后,该引用就会加入到与之关联的引用队列中。(软引用可以用来实现内存敏感的高速缓存
)当发生GC时候,无论当前内存是否足够,弱引用所引用的对象都会被回收掉
)。弱引用也是和一个引用队列联合使用,如果弱引用的对象被垃圾回收期回收掉,JVM会将这个引用加入到与之关联的引用队列中。若引用的对象可以通过弱引用的get方法得到,当引用的对象被回收掉之后,再调用get方法就会返回null。public class SoftReferenceDemo { //private static ConcurrentHashMap<String,SoftReference<User>> cacheUser = new ConcurrentHashMap<String,SoftReference<User>>(); public static void main(String[] args) throws InterruptedException { User a = new User(); a.name = "wei"; SoftReference<User> softReference = new SoftReference<User>(a); a = null; System.out.println(softReference.get().name); int i = 0; while (softReference.get() != null) { if (i == 10) { System.gc(); System.out.println("GC"); } Thread.sleep(1000); System.out.println(i); i++; } System.out.println("Finish"); }}
转载地址:http://ysbwz.baihongyu.com/