ThreadLocal的作用是能存储一个跟随线程的变量,线程未结束前你可以设置以及获取值。
* This class provides thread-local variables. These variables differ from * their normal counterparts in that each thread that accesses one (via its * {@code get} or {@code set} method) has its own, independently initialized * copy of the variable.
如下是一个使用ThreadLocal的示例,展示了ThreadLocal的用法。
ThreadLocal设置和获取当前线程的变量值,当线程消亡时,不能通过线程获取变量。
当线程存活时,可以先设置好ThreadLocal的值后,在线程的各个地方都可以拿到该值。
由于ThreadLocal使用的是WeakReference,可能出现垃圾回收,所以慎重使用。
ThreadA.java
package com.example.demo.concurrent.threadlocal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ThreadA extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
ThreadLocalTool.local.set("ThreadA"+(i+1));
log.info("ThreadA{}, get value:{}",i+1, ThreadLocalTool.local.get());
TimeUnit.MICROSECONDS.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.example.demo.concurrent.threadlocal;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ThreadB extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
ThreadLocalTool.local.set("ThreadB"+(i+1));
log.info("ThreadB{}, get value:{}",i+1, ThreadLocalTool.local.get());
TimeUnit.MICROSECONDS.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadLocalDemo.java
package com.example.demo.concurrent.threadlocal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ThreadLocalDemo {
public static ThreadLocalExt local = new ThreadLocalExt();
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.start();
threadB.start();
try {
for (int i = 0; i < 10; i++) {
if (i==0){
log.info("Thread_Main{}初始值为:{}",i+1, local.get());
}
ThreadLocalTool.local.set("Thread_Main"+(i+1));
log.info("Thread_Main{}, get value:{}",i+1, ThreadLocalTool.local.get());
TimeUnit.MICROSECONDS.sleep(200);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果是:
01:04:15.189 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA1, get value:ThreadA1
01:04:15.189 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main1初始值为:ThreadLocal default value.
01:04:15.189 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB1, get value:ThreadB1
01:04:15.199 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main1, get value:Thread_Main1
01:04:15.200 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA2, get value:ThreadA2
01:04:15.201 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB2, get value:ThreadB2
01:04:15.201 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main2, get value:Thread_Main2
01:04:15.202 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA3, get value:ThreadA3
01:04:15.203 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main3, get value:Thread_Main3
01:04:15.203 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB3, get value:ThreadB3
01:04:15.204 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main4, get value:Thread_Main4
01:04:15.204 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB4, get value:ThreadB4
01:04:15.204 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA4, get value:ThreadA4
01:04:15.206 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main5, get value:Thread_Main5
01:04:15.206 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB5, get value:ThreadB5
01:04:15.206 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA5, get value:ThreadA5
01:04:15.208 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA6, get value:ThreadA6
01:04:15.208 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB6, get value:ThreadB6
01:04:15.208 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main6, get value:Thread_Main6
01:04:15.210 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA7, get value:ThreadA7
01:04:15.210 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main7, get value:Thread_Main7
01:04:15.210 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB7, get value:ThreadB7
01:04:15.212 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main8, get value:Thread_Main8
01:04:15.212 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA8, get value:ThreadA8
01:04:15.212 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB8, get value:ThreadB8
01:04:15.214 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB9, get value:ThreadB9
01:04:15.216 [Thread-1] INFO com.example.demo.concurrent.threadlocal.ThreadB - ThreadB10, get value:ThreadB10
01:04:15.217 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA9, get value:ThreadA9
01:04:15.217 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main9, get value:Thread_Main9
01:04:15.219 [main] INFO com.example.demo.concurrent.threadlocal.ThreadLocalDemo - Thread_Main10, get value:Thread_Main10
01:04:15.219 [Thread-0] INFO com.example.demo.concurrent.threadlocal.ThreadA - ThreadA10, get value:ThreadA10
ThreadLocal的核心是ThreadLocal.ThreadLocalMap,ThreadLocalMap与HashMap类似,都是存储的key、value数据,key是当前线程,value就是set()方法的值。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
详细解析可以参考ThreadLocal源码解读