0.简介:创建线程局部变量的类

使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。

  • 内部类ThreadLocalMap实现,key是变量,value是所在的线程。

用法如下:

private void testThreadLocal() {
Thread t = new Thread() {
ThreadLocal<String> mStringThreadLocal = new ThreadLocal<>(); @Override
public void run() {
super.run();
mStringThreadLocal.set("localValue"); // 设置值
mStringThreadLocal.get(); // 获取值
}
}; t.start();
}

1.如何实现:依靠内部类ThreadLocalMap

set是如何实现的?

  • 首先获取当前线程
  • 利用当前线程作为句柄获取一个ThreadLocalMap的对象
  • 如果ThreadLocalMap对象不为空,则设置值;否则创建这个ThreadLocalMap对象并设置值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

下面是一个利用Thread对象作为句柄获取ThreadLocalMap对象的代码:

ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

可以看出一个Thread实例就有一个ThreadLocalMap对象。

get是如何实现的

public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}

3.总结

实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

ThreadLocal的实例以及其值仍然存放在JVM的堆。

4.问题

4.1 ThreadLocal会导致内存泄露么

如果应用使用了线程池,那么之前的线程实例处理完之后,会再次被复用,所以ThreadLocal变量会一直存在。

  • 不会发生内存泄露,ThreadLocalMap的内部实现是弱引用的,可以被JVM回收。
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;
}
}
}

4.2 使用场景

  • 实现单个线程单例以及单个线程上下文信息存储,比如交易id等
  • 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例
  • 承载一些线程相关的数据,避免在方法中来回传递参数

最新文章

  1. 《月之猎人 (Moon Hunters)》主角设计
  2. FFmpeg滤镜实现区域视频增强 及 D3D实现视频播放区的拉大缩小
  3. hash模块 hashlib 和hmac
  4. 【SSM 8】spring集成Mybatis通用Mapper
  5. KVM 介绍(3):I/O 全虚拟化和准虚拟化 [KVM I/O QEMU Full-Virtualizaiton Para-virtualization]
  6. Android开发-API指南-&lt;grant-uri-permission&gt;
  7. [现代程序设计]homework-03
  8. 使用LoadRunner对Web Services进行调用--Add Service Call
  9. js求字符长度
  10. js“分享到”侧边框伸缩实现
  11. RandomAccessFile类初次使用
  12. Spring-Cloud(三)Eureka注册中心实现高可用
  13. ie11的版本判断
  14. Git-撤销(回退)已经add,commit或push的提交
  15. pandas.DataFrame
  16. Deep Learning Terminologies
  17. 利用wsdl2java工具生成webservice的客户端代码
  18. linux中的signal机制(转)
  19. 使用SqlServer中的float类型时发现的问题
  20. Notepad++下载需要的插件(如何在Notepad++中手动下载需要的插件)

热门文章

  1. 复杂PC问题——信号量与共享存储区
  2. 个人作业4——alpha阶段个人总结(201521123003 董美凤)
  3. Alpha版本冲刺(八)
  4. webpack命令局部运行的几种方法
  5. Java 基础--小结
  6. hihocoder1711 评论框排版[并查集+set]
  7. 中行P1签名及验签
  8. Linux及安全实践三——程序破解
  9. Java之Java程序与虚拟机
  10. React-Router 动画 Animation