概念
ThreadLoacl主要是用来做线程间共享但又不关联的共享变量的存储。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,也就是只是共用这个变量以及该变量的初始值,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadLocalTest {
public void test(){
ThreadLocal<Integer> local = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
ExecutorService service = Executors.newFixedThreadPool(3);
for(int i=0;i<3;i++){
service.execute(new Runnable() {
@Override
public void run() {
Integer num = local.get();
Integer init = num;
while(++num<10);
System.out.println("当前线程为:" + Thread.currentThread().getName() + ",初始值为:"+init+",结果数据为:" + num);
}
});
}
service.shutdown();
}
public static void main(String[] args) {
new ThreadLocalTest().test();
}
}
当前线程为:pool-1-thread-1,初始值为:0,结果数据为:10
当前线程为:pool-1-thread-3,初始值为:0,结果数据为:10
当前线程为:pool-1-thread-2,初始值为:0,结果数据为:10
通过测试代码可以看到,虽然三个线程使用了同一个ThreadLocal变量,并各自进行加到10操作,但是三个线程之间并没有相互影响,而只是共享了变量初始值。
ThreadLocal源码分析
1. get()
首先查看ThreadLocal构造方法,发现什么也没做,那么查看get()方法:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
可以看到get方法首先取得当前线程对象,接着借此调用getMap方法返回ThreadLocalMap对象。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
而getMap方法最终是从当前线程中取得ThreadLocalMap实例,查看线程类:
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
发现它是线程类的实例成员,也就是说,每一个线程都有自己独立的ThreadLocalMap实例。
在我们第一次调用ThreadLocal的get()方法时,getMap()方法返回是null(这一点可以通过查看Thread类的构造方法最终执行的init方法发现,构造线程时没有对ThreadLocal.ThreadLocalMap threadLocals进行初始化),所以执行了setInitialValue方法。
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
其中initialValue()方法就是我们重写过的方法,在上面的例子中我们返回的是0.由于是第一次执行,getMap(t)方法方的是null,所以接着看createMap方法:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
终于创建了当前线程t的ThreadLocalMap,其中参数this为当前ThreadLocal实例,firstValue为其初始值:
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
在ThreadLocalMap构造方法中,创建了一个类似Map的对象,并且以ThreadLocal实例为key,initialValue()方法的返回值为value。所以每一个线程都有一个独立的这样的ThreadLocalMap对象将ThreadLocal实例与其值关联起来。
接下来,如果第二次调用get()方法,会怎么样呢?
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
由于getMap(t)不再返回null,所以进入if块,然后以当前ThreadLocal实例为Key,取得当前线程的ThreadLocalMap中对应的值,当然如果发现不存在这样的键值对entry,那么还是进行执行setInitialValue.
2. set(T value)
这个方法就是重新设置每一个线程的本地ThreadLocal变量的值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
这里取得当前线程,然后根据当前的thradLocal实例取得其map。然后重新设置 map.set(this, value);这时这个线程的thradLocal里的变量副本就被重新设置值了!
3. remove()
就是清空ThreadLocalMap里的key-value键值对,这样一来。下次再调用get时又会调用initialValue这个方法返回设置的初始值.
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
总结:
1、每个线程都有自己的局部变量
每个线程都有一个独立于其他线程的上下文ThreadLocalMap来保存这个变量。
2、独立于变量的初始化副本
ThreadLocal可以给一个初始值,而每个线程都会获得这个初始化值的一个副本,这样才能保证不同的线程都有一份拷贝。
3、状态与某一个线程相关联
ThreadLocal 不是用于解决共享变量的问题的,也不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制。
分享到:
相关推荐
ThreadLocal是Java编程语言中的一个类,用于在多线程环境下提供线程局部变量。它为每个线程创建了一个独立的变量副本,每个线程只能访问自己的副本,不会影响其他线程。这种机制有助于实现线程安全,尤其在需要线程...
java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...
本话题聚焦于“多线程线程变量赋值”,讨论如何在不通过参数传递的情况下,为线程变量直接赋值。 首先,我们需要理解线程变量(Thread Local Variables)的概念。线程变量,也称为线程局部变量,是一种特殊类型的...
Java 线程本地变量 ThreadLocal 详解 ThreadLocal 是 Java 中的一个类,提供了线程安全的对象封装,用于解决多线程访问数据的冲突问题。ThreadLocal 的主要目的是为每个线程提供一个变量副本,从而隔离了多个线程...
在Java中,可以使用`ThreadLocal`类来创建线程本地变量。使用本地变量可以简化代码,因为不需要进行同步操作,但需要注意的是,如果变量不再使用,记得及时清理,防止内存泄漏。 **Lock锁** Lock锁是一种显式同步...
- 使用`ThreadLocal`存储线程私有数据,避免全局变量的干扰。 理解并掌握Java多线程下变量共享的原理和解决方案,有助于编写出高效、稳定的并发程序。在实际开发中,应结合具体业务场景选择合适的同步机制,以达到...
ThreadLocal并不是线程的本地实现,而是一个线程局部变量,它为每个线程提供了一个变量的副本,确保每个线程都可以独立地操作自己的副本,而不干扰其他线程。因此,ThreadLocal可以帮助我们在多线程环境下为每个线程...
Java中的ThreadLocal是一种特殊类型的变量,它主要用于在多线程环境下提供线程范围内的局部变量。每个线程都拥有自己独立的ThreadLocal变量副本,互不影响。这与传统的全局变量不同,全局变量在所有线程间共享,可能...
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...
ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...
ThreadLocal的实现原理可以总结为:每个线程都有一个自己的ThreadLocalMap,用于存放线程的本地变量;ThreadLocal的set、get、remove方法都是基于ThreadLocalMap的操作。 ThreadLocal的优点是可以解决多线程访问...
随后的每次`get()`调用都将返回该线程本地变量的副本,从而保证了线程之间的隔离性。 #### 三、ThreadLocal的设置与获取 `ThreadLocal`提供了两个关键的方法: - `set(T value)`:用于将特定线程局部变量的值设为...
ThreadLocal是Java编程语言中的一个强大工具,它主要用于在多线程环境中为每个线程提供独立的变量副本。这个机制确保了线程之间的数据隔离,避免了共享状态带来的并发问题,提高了程序的安全性和效率。ThreadLocal是...
在多线程环境下,ThreadLocal 变量可以保证各个线程的变量相对独立于其他线程内的变量。这种机制可以帮助开发者在多线程环境下编写更加简洁、可维护的代码。 ThreadLocal 的作用 ThreadLocal 的主要作用是提供线程...
Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...
`ThreadLocal`并非一个线程,而是一种为线程提供局部变量的机制。它允许每个线程都拥有一个独立的变量副本,从而避免了线程间的数据共享问题,简化了多线程编程的复杂度。 #### 三、`ThreadLocal`的基本原理 `...
在这个例子中,`ThreadLocalTest`类中的`threadLocal`变量为每个线程初始化一个随机值,并且`increament()`方法会增加当前线程的`ThreadLocal`变量的值。由于每个线程都有自己的副本,因此不会发生数据竞争。 总结...
Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的概念,主要用于在多线程环境中为每个线程提供独立的变量副本。ThreadLocal不是一种数据结构,而是一种解决线程间共享数据的方式,它提供了线程安全的局部...
从线程的角度看,目标变量就像是一个线程的本地变量,这也是类名中“Local”所要表达的意思。ThreadLocal 并不是 Java 的新发明,而是一个变相地通过 ThreadLocal 的类提供支持的解决方案。 ThreadLocal 类中的方法...