Java ThreadLocal 的用法
2019-07-31 本文已影响0人
oO白眉大虾Oo
前言
ThreadLocal提供了线程局部变量,当前线程全局共享,线程隔离。
源码实现
public class ThreadLocal<T> {
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
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();
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
}
线程局部变量是存储在ThreadLocalMap中,并以当前线程作为KEY
注意:当采用了线程池技术后,线程是不被销毁的,局部变量不会被清除,故最好是在线程结束时remove下
模拟线程池局部变量缓存的请求
public class Context {
private static final ThreadLocal<Integer> userId = new ThreadLocal<>();
public static void set(Integer userId) {
Context.userId.set(userId);
}
public static Integer get() {
return Context.userId.get();
}
public static void unset() {
if (Context.userId != null) {
Context.userId.remove();
}
}
}
public class Service {
public void print() {
System.out.println(Thread.currentThread().getName() + " service geted userid : " + Context.get());
}
}
public class App {
public static void main(String[] args) {
LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue();
// 线程池设置上限为5个
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 3, TimeUnit.SECONDS, linkedBlockingQueue);
for (int i = 0; i < 20; i++) {
final int finalI = i % 10 == 0 ? -1 : i;
executor.execute(new Runnable() {
@Override public void run() {
if (finalI != -1) {
Context.set(finalI);
}
new Service().print();
// Context.unset();
}
});
}
}
}
// 输出:
pool-1-thread-2 service geted userid : 1
pool-1-thread-3 service geted userid : 2
pool-1-thread-4 service geted userid : 3
pool-1-thread-1 service geted userid : null
pool-1-thread-5 service geted userid : 4
pool-1-thread-2 service geted userid : 5
pool-1-thread-1 service geted userid : 8
pool-1-thread-4 service geted userid : 7
pool-1-thread-3 service geted userid : 6
pool-1-thread-4 service geted userid : 12
pool-1-thread-1 service geted userid : 11
pool-1-thread-2 service geted userid : 5
pool-1-thread-5 service geted userid : 9
pool-1-thread-2 service geted userid : 16
pool-1-thread-1 service geted userid : 15
pool-1-thread-4 service geted userid : 14
pool-1-thread-3 service geted userid : 13
pool-1-thread-4 service geted userid : 19
pool-1-thread-2 service geted userid : 18
pool-1-thread-5 service geted userid : 17
// 出现了重复数据,证明了数据缓存的问题
// 解决办法也简单,在Context.unset()启用即可
// 启用后的结果
pool-1-thread-2 service geted userid : 1
pool-1-thread-1 service geted userid : null
pool-1-thread-3 service geted userid : 2
pool-1-thread-4 service geted userid : 3
pool-1-thread-5 service geted userid : 4
pool-1-thread-2 service geted userid : 5
pool-1-thread-2 service geted userid : 6
pool-1-thread-1 service geted userid : 7
pool-1-thread-2 service geted userid : null
pool-1-thread-4 service geted userid : 9
pool-1-thread-3 service geted userid : 8
pool-1-thread-4 service geted userid : 14
pool-1-thread-2 service geted userid : 13
pool-1-thread-1 service geted userid : 12
pool-1-thread-5 service geted userid : 11
pool-1-thread-1 service geted userid : 18
pool-1-thread-2 service geted userid : 17
pool-1-thread-4 service geted userid : 16
pool-1-thread-3 service geted userid : 15
pool-1-thread-5 service geted userid : 19