- 用法
ThreadLocal tl = new ThreadLocal<>() 这里的T是任意对象
t1.get() 从ThreadLocal中取
t1.set(Object) 放入ThreadLocal
注:
ThreadLocal中的值和对象只是针对自己线程的。两个线程对同一个t1对象的读写是隔离的。
- 源码实现
①:以set()方法为例(比如T是一个叫Person的类)
内部是有一个Map
ThreadLocal.java:Thread.currentThread()获取了当前线程
这里的getMap(t)进入,发现获取了一个ThreadLocalMap,这个map是在Thread中:
总结上面Thread.currentThread.map(ThreadLocal, person)获取了当前线程中的一个map中,所以其实不是一个map用不同Thread做key的隔离,实际上是不同的Thread用不同的map。
这个ThreadLocalMap内可以存在多个key:value,key是ThreadLocal,value是set进来的对象,每个ThreadLocal只能set自己的,那么代表这个map是全局通用的,每个声明的ThreadLocal.set()时,都会对同一个map.put()内容。
- ThreadLocal用途
声明式事务,保证同一个connection(例如配置中有四项都是要连接数据库,就可以合并成为一个事务,但是不同的连接之间肯定不能合并为一个事务,那么第一个取的时候把这个connection放入本地线程的ThreadLocal中,以后的连接实际上都是从这个ThreadLocal中来取,保证是同一个链接,这部分知识应该是基础中的)
=========================================================================
引用一共四种:强、软、弱、虚
- 强引用:
普通的引用就是强引用(Object o = new Object())
垃圾回收时,有引用指向的空间一定不会被回收,也就是强引用不会被垃圾回收,除非下面你Object o = null,然后调用了System.gc(),System.in.read()(这句话是为了阻塞当前线程的,没有特殊含义,因为gc是跑在别的线程中的,这样阻塞一下main的线程,防止main结束,要是main结束了,gc也没啥意义了)
- 软引用:
一个对象若只有一个软引用指向他,只有当系统堆内存不够用时才会被回收。
SoftReference。下图中m指向了一个softReference软引用,这个软引用指向了一个字节数组。
用途:做缓存用,比如说从数据库取了一堆数据,需要用直接存缓存取,空间不够了就可以去掉,平时很难用到。
- 弱引用(面试重点):
只要遭遇到gc就会回收
weakReference。下图中m只想了一个weakReference弱引用,这个弱引用指向了M对象,这个声明之后直接system.gc()就null了。
用途:这个M对象若除了这个弱引用还有个强引用指向它,那么当强引用消失之后,这个对象就应该被回收。
一般用在容器中
在ThreadLocal(基本上下图就是ThreadLocal面试能问到的最深处)中应用(实线是强引用,虚线是弱引用,tl是声明的ThreadLocal对象):
ThreadLocal中发现Entry(map中是entry这个key:value)的key实际上是一个弱引用指向ThreadLocal(因为内部的map的key是ThreadLocal),源码如下图(ThreadLocal内):
若key指向ThreadLocal是强引用,那么tl这个ThreadLocal的声明都不指向这个ThreadLocal时,那么因为ThreadLocal有强引用指向他,所以他永远不会被回收,而有些游戏服务器之类的,可能这个Thread永远不会停,那么这块区域就会永远不被回收,这块就发生了内存泄漏,单这个key若是弱引用的话,tl消失时这个指向的ThreadLocal就被回收了,因为tl都不指向这里了,map指向这个ThreadLocal没意义了所以无影响。
补充知识(内存泄漏:内存中有一块永远不会被回收。 OOM:内存分配不够使了。 完全不同的概念)。
ThreadLocal的坑:
key指向的弱引用,回收之后key变成了null,但是这个map永远存在的,所以这个value还是指向了另外的对象,所以ThreadLocal在每次使用完之后一定要手工tl.remove()回收ThreadLocal,否则这个map越来越大之后还是会在发生内存泄漏,慢慢的OOM了!如下图:
- 虚引用:
主要是处理堆外内存的。
PhantomReference,声明的条件苛刻,第二个必须是一个队列。
虚引用被垃圾回收发现直接就会被干掉,被干掉时放入声明时的那个队列中一个值,检测队列中出现了值就代表虚引用被干掉了,往队列中扔一个值就是虚引用被干掉通知的方式。
PhantomReference.get(),无论什么时候都拿不到值(不像上面那几个有引用就能拿到,这里有了也拿不到)。
用途:基本用不上,给写JVM人用的,写netty之类的也可以,一般他们都会监控这个队列,发现被通知之后就会做出一些处理
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-9IQ4FEZZ-1710923699862)]