Java多线程之ThreadLocal

简介

这个类提供线程局部变量。这些变量与普通变量的不同之处在于,每个访问一个变量(通过其get或set方法)的线程都有自己的独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态字段,希望将状态与线程关联(例如,用户ID或事务ID)。

使用

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ThreadLocalDemo {

private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

public static void main(String[] args) {
//主线程
threadLocal.set("main thread.");
System.out.println("Thread name:" + Thread.currentThread().getName() + "<-->" + threadLocal.get());
//线程1
new Thread(() -> {
threadLocal.set("This is thread one.");
System.out.println("Thread name:" + Thread.currentThread().getName() + "<-->" + threadLocal.get());
}, "Thread one").start();
//线程2
new Thread(() -> {
threadLocal.set("This is thread two.");
System.out.println("Thread name:" + Thread.currentThread().getName() + "<-->" + threadLocal.get());
}, "Thread two").start();
//线程3
new Thread(() -> {
threadLocal.set("This is thread three.");
System.out.println("Thread name:" + Thread.currentThread().getName() + "<-->" + threadLocal.get());
}, "Thread three").start();
}
}

代码运行

1
2
3
4
5
Thread name:main<-->main thread.
Thread name:Thread one<-->This is thread one.
Thread name:Thread two<-->This is thread two.
Thread name:Thread three<-->This is thread three.

Java实现过程

set方法实现过程

  • 尝试获取或创建ThreadLocalMap
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    map.set(this, value);
    } else {
    createMap(t, value);
    }
    }
  • 创建ThreadLocalMap并赋值个ThreadLocal私有变量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /**
    * Create the map associated with a ThreadLocal. Overridden in
    * InheritableThreadLocal.
    *
    * @param t the current thread
    * @param firstValue value for the initial entry of the map
    */
    void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
  • 获取一个ThreadLocalMap
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * Get the map associated with a ThreadLocal. Overridden in
    * InheritableThreadLocal.
    *
    * @param t the current thread
    * @return the map
    */
    ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
    }

get方法实现过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
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();
}

很明显,每一个Thread对象有一个私有的ThreadLocalMap对象。操作set数据时候,数据是设置到当前操作Thread上面的ThreadLocalMap,从而保证了数据的独立性。

ThreadLocalMap

ThreadLocalMap是一个定制的散列映射,仅适用于维护线程本地值。没有任何操作被导出到ThreadLocal类之外。这个类是包私有的,允许在Thread类中声明字段。为了帮助处理非常大的和长期存在的使用,散列表项使用WeakReferences作为键。但是,由于不使用引用队列,只有当表空间耗尽时,才会删除陈旧的表项。

Author: suce
Link: https://haoubox.cn/2021/05/11/Java多线程之ThreadLocal/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.