entry节点不为null,entry节点的key和参数key不同
从i节点开始往后找,如果有key值相同的节点,也就是我们找到了我们需要的节点,返回entry即可。如果找不到,从i节点往后找,遇到key为null的回收一下该节点后返回null,遇到entry为null的直接返回null;
getEntry()方法会被ThreadLocal的get()方法调用,我们会在稍后的ThreadLocal源码的讲解中再谈。
介绍ThreadLocalMap用了不少的篇幅啊!下面就来看看我们ThreadLocal啦!关于ThreadLocal的方法网上已经有太多太多的文章介绍了。不过这里我们还是简单的结合我们上面所说的ThreadLocalMap来总结一下!
当我们调用ThreadLocal对象的set方法时,程序会获取当前线程,并将其作为作为参数传递给getMap()方法。
Thread.java ThreadLocal.ThreadLocalMap threadLocals = null; ThreadLocal.java ThreadLocal.ThreadLocalMap threadLocals = null; ThreadLocalMap getMap(Thread t) { return t.threadLocals; } 查看Thread类源码可以发现,Thread类中包含了一个ThreadLocalMap对象,这个家伙我们上面已经花了很大的篇幅来说了,简单的说它的key为ThreadLocal的弱引用,而value为待保存的对象。至于为什么是弱引用,大家自己去google下。
继续说getMap()方法。getMap()方法很简单:返回当前线程中的ThreadLocalMap对象。
获取到ThreadLocalMap对象后,如果它不为空。则往该对象里面塞入一个键值对,key为ThreadLocal对象的弱引用,vaule为需要保存的对象。
如果ThreadLocalMap对象为null,则调用createMap()方法。
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } createMap()方法在这里不细说。它会初始化当前线程的ThreadLocalMap对象,并将当前需要保存的对象放入ThreadLocalMap中,key值为当前线程的弱引用对象。
小结一下:ThreadLocal的set方法会获取当前线程的ThreadLocalMap对象,如果TreadLocalMap对象不为空,则将当前线程的弱引用作用key,待保存对象作为value保存起来;若ThreadLocalMap对象为null,则会先初始化,再放入键值对。
知道了怎么放,接下来聊一聊怎么取。眼尖的朋友们肯定已经发现了,这里又出现了ThreadLocalMap对象。那是自然,因为我们上面不就是往ThreadLocalMap里面放的吗!还记得ThreadLocalMap里面存了啥不?不记得的往上翻一翻。
如果ThreadLocalMap对象不为空,当前线程作为key值,从ThreadLocalMap中取出来了一个ThreadLocalMap.Entry对象。这个getEntry()方法我们在上面已经已经介绍过了,可能再返回去看看。当然了,肯定有人要问!我们刚才放的时候放的明明不是ThreadLocalMap.Entry对象!这咋回事呢?
实际上,在ThreadLocalMap中有一个静态类,它名叫Entry,继承了WeakReference类。再看看Entry的构造方法。如果调用Entry的get方法,实际上拿到的是ThreadLocal对象的弱引用对象。是不是很熟悉?上面的set方法有聊到过。
继续说上面的get()方法。当我们拿到了Entry对象后,如果Entry对象不为空,直接返回Entry对象的value值,即我们想要的值。
那么如果ThreadLocalMap为空呢?则会执行setInitialValue()方法。光看名字,你肯定觉得它无非执行了两步操作:1.初始化对象;2. 将初始化后的对象塞入ThreadLocalMap对象中;3. 返回初始化后的对象。那我们来看看我们的猜想对不对呢?