问题:当线程池与ThreadLocal
共用时,ThreadLocal
读取数据出现错乱。
问题验证:
public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);final ThreadLocal<String> threadLocal = new ThreadLocal<String>();Runnable runnable = () -> {System.out.println(threadLocal.get());threadLocal.set(Thread.currentThread().getName() + ": name");};for (int i = 0; i < 6; i++) {executorService.submit(runnable);}executorService.shutdown();}
结果输出:
null
null
pool-1-thread-1: name
pool-1-thread-2: name
pool-1-thread-1: name
pool-1-thread-2: name
由此可以看到,当我们在线程池中获取ThreadLocal
内容时出现错乱。这是因为线程池会复用线程对象,与线程对象绑定的类的静态属性ThreadLocal
变量也会被重用,这就导致一个线程可能获取到其他线程的ThreadLocal
值。
非线程池情况下:
public static void main(String[] args) {final ThreadLocal<String> threadLocal = new ThreadLocal<String>();for (int i = 0; i < 6; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println(threadLocal.get());threadLocal.set(Thread.currentThread().getName() + ": name");}});thread.start();}}
结果输出:
null
null
null
null
null
null
内容获取正常
总结:
ThreadLocal
属于线程,于线程创建而生,线程结束而自然销毁,本来是没什么问题的。在线程池中,线程并不会用完了而销毁,而是会放回到线程池中,这时候ThreadLocal
里存放的数据还在。下一个请求来了从线程池中拿到这个线程,就会获取到上次请求存放的数据。
所以每次使用完ThreadLocal
就调用remove
将其删掉。