public class ThreadLocalExample {
private static final ThreadLocal<String> threadLocalVariable = new ThreadLocal<>();
public static void main(String[] args) {
// 创建并启动两个线程
Thread thread1 = new Thread(() -> {
// 在线程1中设置 ThreadLocal 变量的值
threadLocalVariable.set("Value from Thread 1");
printThreadLocalVariable();
});
Thread thread2 = new Thread(() -> {
// 在线程2中设置 ThreadLocal 变量的值
threadLocalVariable.set("Value from Thread 2");
printThreadLocalVariable();
});
thread1.start();
thread2.start();
}
// 打印 ThreadLocal 变量的值
private static void printThreadLocalVariable() {
// 获取当前线程的 ThreadLocal 变量的值
String value = threadLocalVariable.get();
System.out.println("Thread: " + Thread.currentThread().getName() + ", ThreadLocal Variable Value: " + value);
// 清理 ThreadLocal 变量,确保不影响其他线程
threadLocalVariable.remove();
}
}
问题:thread1与thread2会有并发问题吗?会不会出现thread1调用threadLocalVariable.set(“Value from Thread 1”)>>thread2调用threadLocalVariable.set(“Value from Thread 2”)>>thread1调用printThreadLocalVariable()读取到"Value from Thread 2"的情况?
答案:肯定不会,表面看thread1与thread2在修改共享资源,其实内部修改的是当前线程Thread.currentThread(),ThreadLocal仅仅至少一个key并没有被修改.
源码分析
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 getMap(Thread t) {
return t.threadLocals;
}
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();
}
@Slf4j
public class UserUtil {
private static final ThreadLocal<UserInfo> threadLocal = new TransmittableThreadLocal<>();
public static UserInfo getUser() {
return threadLocal.get();
}
public static void setUser(UserInfo adminUser) {
threadLocal.set(adminUser);
}
public static void removeUser() {
threadLocal.remove();
}
}
简化代码
@Around("(execution(* com.lxw.*.controller..*(..))")
public Object around(ProceedingJoinPoint point) throws Throwable {
try {
ServletRequestAttributes attributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader(Const.TOKEN_NAME);
if (StrUtil.isNotEmpty(token)) {
UserInfo userInfo = redis.get(token);
UserUtil.setUser(userInfo);
}
return point.proceed();
} finally {
UserUtil.removeUser();
}
}
package org.springframework.web.context.request;
public abstract class RequestContextHolder {
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
if (attributes == null) {
attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();
}
return attributes;
}
}