引入主题
|
每个线程对全局共享变量的修改 互相之间不会产生影响 实现线程的隔离
应用场景:数据库连接 全局用户信息存储
经典案例 SimpleDateFormat 非线程安全的
|
查看SimpleDateFormat 源码
|
解决方式
1,可以加锁,避免竞争
public synchronized static Date parse(String strDate) { try { return sdf.parse(strDate); } catch (ParseException e) { e.printStackTrace(); } return null; }
2,线程隔离 让每个线程使用的SimpleDateFormat 都是各自的
|
常用方法
set()
在当前线程范围内,设置一个值存储到ThreadLocal中,这个值仅仅对当前线程可见,相当于在当前线程范围内建立一个副本
get()
从当前线程范围内取出set()方法设置的值
remove()
移除当前线程存储的值
withInitial()
java8提供,快速初始化一个threadLocal
原理分析
能够实现线程的隔离 线程私有
存储副本,需要一个容器 数据结构
get()方法 key为当前线程
下方示例图 表示一个线程会有多个ThreadLocal 对象
private ThreadLocal local1;
private ThreadLocal local2;
源码分析
set()
|
key的清理过程1 示意图 向前有脏Entry slotToExpunge值发生变化 向后查找到可覆盖的Entry 发现冲突 覆盖值并且交换位置
key的清理过程2 示意图 向前有脏Entry slotToExpunge值发生变化 向后未查找到可覆盖的Entry 往后查找没有key冲突直接覆盖staleSlot处的值不需要替换
key的清理过程3 示意图 向前没有脏Entry slotToExpunge值不变化 向后查找到可覆盖的Entry 发现key冲突 覆盖值并且交换位置
key的清理过程4 示意图 向前没有脏Entry slotToExpunge值不变化 向后查未找到可覆盖的Entry 往后查找没有key冲突直接覆盖staleSlot处的值不需要替换
具体的清理代码如下,就是该entry[i]位置 元素=null
|
解决hash冲突的常用方法
方法 | 应用场景 | 备注 | |
---|---|---|---|
开放寻址法-线性探索 | threadlocal | ||
链式寻址法 | hashmap | ||
再hash |
java对象引用关系
强引用 :存在强引用的对象=null 后,垃圾回收器不会回收它
软引用
弱引用:存在弱引用的对象=null 后,垃圾回收器会回收它
虚饮用
get()
|
内存泄露的问题
key=null ,value没有引用指向 清理无效key 的过程可能会清理不到,占用空间 浪费内存 引发内存泄露
解决方法:使用完以后 调用remove()方法 不存在空引用指向 内存就会被释放
|