可能大部分人的想法和我当初的想法一样,都是以为在ThreadLocal里使用一个Map,这个Map的键为Thread,值为绑定的变量。其实如果这样做是有问题的:
1. 就是当线程回收时,该线程绑定的变量不能被自动的回收,因为变量存储在ThreadLocal里,必须显式的去回收。如果此变量存储在线程里,那么线程回收时,这个变量没有被其他引用指向的话,它便随着线程一起回收。
2. 另外不这样做还有一个好处:如果Map在ThreadLocal里,那你必须得考虑线程同步访问这个Map,但是这确实没有必要,因为线程访问自己的变量,和其他线程没有直接的关系,所以把Map放在线程里,就不需要做同步的处理,这样即加快了访问的速度。
其实实现不是这样的:每个线程都包含一个ThreadLocal.ThreadLocalMap变量threadLocals(延迟创建的),这个映射(Map)目的就是为每个线程存储关联到使用到的不同ThreadLocal的变量,这个很好理解,因为,一个线程可能使用到多个不同的ThreadLocal对象,每一个ThreadLocal对象的值都被认为是不同的。于是,每次调用ThreadLocal的get()方法,其实就是获取当前线程(Thread.currentThread()),然后从threadLocals映射里,根据ThreadLocal对象,找出其关联的拷贝,这个值便是当前线程的,隔离于其他线程的值。
我们知道,ThreadLocal.ThreadLocalMap映射使用的键是被WeakReference包装的ThreadLocal对象,如果ThreadLocal对象没有其他强引用和软引用指向时,该线程也不会继续持有ThreadLocal对象,因为根据JVM规范,它会被垃圾回收器下次回收时销毁,这一定程度避免了内存泄露,但不表示不会出现内存泄露,关于ThreadLocal引起的内存泄露,特别是导致ClassLoader不能被回收,网上有很多文章都在讨论。在Java 1.5开始,加入了remove()方法,这样我们可以显式的调用此方法,释放内存,所以使用ThreadLocal要特别注意内存泄露的问题。
看来大家对ThreadLocal内存泄露的原因有点误解,其导致Classloader内存泄露的原因在这篇博文写的很清楚了
Classloader leaks:,我在这里补充一下,jvm规范下的classloader能被回收的条件是,所有该classloader产生的所有对象都被回收了:我们知道,对象有一个隐式的引用指向它的类型class对象,而class对象有个隐式的引用指向它的classloader,所以如果有一个对象不回收,那么
可能导致整个classloader不能够被回收。根据sun的关于Perm回收的文章回应,perm在每次老生代(Tenured/Old generation)收集前回收。但是由于泄露,可能多次导致classloader不能被回收而引发Perm最终泄露。在Java 8里,开始不再使用Perm generation,会和JRockit等一样,使用Meta space放置class对象,这无疑是一个好消息。
特此申明一下,我的书籍http://redhat.iteye.com/admin/blogs/1007884关于4.2.3章节出现了纰漏,当我意识到错误时,花了1-2周来查看此问题,下载了sun jdk1.5版本,1.6版本,1.3版本,1.2版本,以及IBM的jdk代码进行比较,这个纰漏的申明在http://redhat.iteye.com/blog/1057991里,自己置顶,这个理解错误的原因是读取别人(老外)写的博文错误引起的,希望大家能够多读代码,谢谢!
分享到:
相关推荐
然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将详细探讨这些常见的误解。 误区一:ThreadLocal是Java线程的一个实现 ThreadLocal并非Java线程的实现,它只是一个工具类,用于创建线程局部变量。...
ThreadLocal是Java编程语言中...但在使用过程中,开发者需要注意内存管理和避免误解其为一种通用的线程同步机制,以防止潜在问题的发生。了解ThreadLocal的底层实现和工作原理对于优化并发代码和防止内存泄漏至关重要。
描述中提到的“线程局部存储”(TLS,也常被误解为Thread Local Storage)是编程语言中一个重要的特性,特别是在多线程环境下。它允许每个线程拥有自己独立的变量副本,这些副本只对创建它们的线程可见,避免了在...
`ThreadLocal`变量虽然在线程之间隔离,但如果线程池重用线程,之前的线程局部变量可能会影响到后续任务,导致意外的行为。要确保在每次任务开始时清理或重新设置线程局部变量。 6. **不恰当的同步对象选择**: ...
标签“java_interview java_面试_雅虎_360”表明这个压缩包里的内容主要涉及Java语言的面试问题,但同样,雅虎(Yahoo)的提及可能是个误解。我们将重点关注360公司的Java面试要求。 从压缩包中唯一的文件“2016...
了解synchronized、volatile、ThreadLocal等机制,以及ExecutorService和并发工具类。 10. **测试**:编写单元测试和集成测试,确保代码正确性。JUnit是常用的Java测试框架,提倡TDD(测试驱动开发)。 以上只是...
16.1.2 单元测试之误解 16.1.3 单元测试之困境 16.1.4 单元测试基本概念 16.2 JUnit 4快速进阶 16.2.1 JUnit 4概述 16.2.2 JUnit 4生命周期 16.2.3 使用JUnit 16.3 模拟利器Mockito 16.3.1 模拟测试概述 16.3.2 创建...
16.1.2 单元测试之误解 16.1.3 单元测试之困境 16.1.4 单元测试基本概念 16.2 JUnit 4快速进阶 16.2.1 JUnit 4概述 16.2.2 JUnit 4生命周期 16.2.3 使用JUnit 16.3 模拟利器Mockito 16.3.1 模拟测试概述 16.3.2 创建...
5. **多线程与并发**:Java提供了丰富的并发工具,如synchronized、volatile、ThreadLocal等,但误用可能导致线程安全问题。理解并发原理并正确使用这些工具至关重要。 6. **异常处理**:Java的异常处理机制包括try...