提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和认识,希望让大家理解ThreadLocal更加透彻一些。
ThreadLocal是什么
ThreadLocal是一个关于创建线程局部变量的类。
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。
Global && Local
上面的两个修饰看似矛盾,实则不然。
- Global 意思是在当前线程中,任何一个点都可以访问到ThreadLocal的值。
- Local 意思是该线程的ThreadLocal只能被该线程访问,一般情况下其他线程访问不到。
用法简介
创建,支持泛型
1
|
|
set方法
1
|
|
get方法
1
|
|
完整的使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
ThreadLocal初始值
为ThreadLocal设置默认的get初始值,需要重写initialValue
方法,下面是一段代码,我们将默认值修改成了线程的名字
1 2 3 4 5 6 |
|
Android中的应用
在Android中,Looper类就是利用了ThreadLocal的特性,保证每个线程只存在一个Looper对象。
1 2 3 4 5 6 7 |
|
如何实现
为了更好的掌握ThreadLocal,我认为了解其内部实现是很有必要的,这里我们以set方法从起始看一看ThreadLocal的实现原理。
下面是ThreadLocal的set方法,大致意思为
- 首先获取当前线程
- 利用当前线程作为句柄获取一个ThreadLocalMap的对象
- 如果上述ThreadLocalMap对象不为空,则设置值,否则创建这个ThreadLocalMap对象并设置值
源码如下
1 2 3 4 5 6 7 8 |
|
下面是一个利用Thread对象作为句柄获取ThreadLocalMap对象的代码
1 2 3 |
|
上面的代码获取的实际上是Thread对象的threadLocals变量,可参考下面代码
1 2 3 4 5 6 |
|
而如果一开始设置,即ThreadLocalMap对象未创建,则新建ThreadLocalMap对象,并设置初始值。
1 2 3 |
|
总结:实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。
对象存放在哪里
在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
问:那么是不是说ThreadLocal的实例以及其值存放在栈上呢?
其实不是,因为ThreadLocal实例实际上也是被其创建的类持有(更顶端应该是被线程持有)。而ThreadLocal的值其实也是被线程实例持有。
它们都是位于堆上,只是通过一些技巧将可见性修改成了线程可见。
关于堆和栈的比较,请参考Java中的堆和栈的区别
真的只能被一个线程访问么
既然上面提到了ThreadLocal只对当前线程可见,是不是说ThreadLocal的值只能被一个线程访问呢?
使用InheritableThreadLocal可以实现多个线程访问ThreadLocal的值。
如下,我们在主线程中创建一个InheritableThreadLocal的实例,然后在子线程中得到这个InheritableThreadLocal实例设置的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
上面的代码输出的日志信息为
1
|
|
使用InheritableThreadLocal可以将某个线程的ThreadLocal值在其子线程创建时传递过去。因为在线程创建过程中,有相关的处理逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
上面代码就是在线程创建的时候,复制父线程的inheritableThreadLocals的数据。
会导致内存泄露么
有网上讨论说ThreadLocal会导致内存泄露,原因如下
- 首先ThreadLocal实例被线程的ThreadLocalMap实例持有,也可以看成被线程持有。
- 如果应用使用了线程池,那么之前的线程实例处理完之后出于复用的目的依然存活
- 所以,ThreadLocal设定的值被持有,导致内存泄露。
上面的逻辑是清晰的,可是ThreadLocal并不会产生内存泄露,因为ThreadLocalMap在选择key的时候,并不是直接选择ThreadLocal实例,而是ThreadLocal实例的弱引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
所以实际上从ThreadLocal设计角度来说是不会导致内存泄露的。关于弱引用,了解更多,请访问译文:理解Java中的弱引用
使用场景
- 实现单个线程单例以及单个线程上下文信息存储,比如交易id等
- 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例
- 承载一些线程相关的数据,避免在方法中来回传递参数
注意:Android的ThreadLocal与Java实现略有不同,但是原理是一致的。
相关推荐
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,...总之,ThreadLocal是Java多线程编程中的一个强大工具,但使用时需谨慎,理解其工作原理和潜在风险,才能更好地利用它来解决实际问题。
ThreadLocal是Java中用于线程局部变量的一个工具类,它的工作原理主要体现在如何在不同的线程之间隔离变量的副本,确保每个线程拥有自己的独立...理解和掌握ThreadLocal的工作原理对于编写高效并发的Java程序至关重要。
Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...
首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作要么全部执行,要么全部不执行,以确保数据的一致性和完整性。Java事务管理主要体现在JDBC API和一些高级框架如Spring中。在JDBC中...
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...
彻底理解Java中的ThreadLocal ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。使用这个工具类可以很简洁地编写出优美的多线程程序。ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这...
ThreadLocal是Java中一个非常重要的线程安全工具类,它为每个线程提供了一个独立的变量副本,使得每个线程可以独立地修改自己的副本,而不影响其他线程中对应的副本。这种机制使得线程间的变量隔离得以实现,有助于...
在ThreadLocal中,`set()`方法用于设置当前线程的ThreadLocal变量值,`get()`方法用于获取当前线程的ThreadLocal变量值。 ```java threadLocal.set("Hello, ThreadLocal"); String value = threadLocal.get(); ``` ...
在深入理解ThreadLocal之前,我们需要先了解两个关键的概念:ThreadLocalMap和Entry。 ThreadLocalMap是ThreadLocal的一个内部类,它是一个自定义的哈希映射,特别适合存储线程局部变量。ThreadLocalMap并不直接...
Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...
Java中的ThreadLocal类是一个强大的工具,它允许程序员创建线程局部变量。这意味着每个线程都有其自己独立的、不可见的变量副本,从而避免了线程间的数据共享问题,简化了多线程环境下的编程复杂性。ThreadLocal并不...
`ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这不同于普通的静态...
`ThreadLocal`在Java中是一个非常重要的工具类,它为每个线程提供了单独的变量副本,每个线程都可以独立地改变自己副本的值,而不会影响其他线程所对应的副本。`ThreadLocal`的全称是`java.lang.ThreadLocal`,它并...
需要注意的是,ThreadLocal中的变量并不是存储在堆内存中,而是存储在线程的ThreadLocalMap中。 ```java ThreadLocal<String> threadLocal = new ThreadLocal(); threadLocal.set("线程A的值"); // 在线程A中,可以...
深入理解Java内存模型对于编写高效的并发程序至关重要。本文将详细介绍JMM的核心概念、工作原理以及相关的编程实践。 1. **核心概念** - **线程私有区域**: 包括程序计数器、虚拟机栈、本地方法栈,这些区域中的...
在本文中,我们将详细介绍Java ThreadLocal的使用案例,并通过一个实际的优化案例,帮助大家理解ThreadLocal的使用。 ThreadLocal的使用场景 在Java多线程编程中,变量的线程安全是一个非常重要的问题。特别是在...
在Java编程中,ThreadLocal是一个强大的工具,它允许线程拥有自己的局部变量副本,从而避免了多线程环境下的数据共享问题。然而,如果不正确地使用ThreadLocal,可能会导致内存泄露,尤其是在Java EE容器如Tomcat中...
ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...
Java中ThreadLocal工具类(解决多线程程序中并发问题的一种新思路,主要为参数的拷贝问题),感兴趣的话可以查看博文,博文地址:http://blog.csdn.net/otengyue/article/details/38459327
ThreadLocal 是 Java 语言中的一种线程内部数据存储机制,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说无法获取到数据。 ThreadLocal 的设计初衷是:...