使用完ThreadLocal不调用remove方法会导致业务逻辑出错?

不调用remove的demo:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadLocalDemo {

    private static ExecutorService executorService = Executors.newFixedThreadPool(3);
    private static ThreadLocal<String> threadLocal = new ThreadLocal();

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            int j = i + 1;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "---设值前threadLocal=" + threadLocal.get());
                    threadLocal.set(Thread.currentThread().getName() + " and 第" + j + "个请求");
                    System.out.println(Thread.currentThread().getName() + "---设值后threadLocal=" + threadLocal.get());
                }
            });
        }
        executorService.shutdown();
    }
}

运行结果如下:
使用完ThreadLocal不调用remove方法会导致业务逻辑出错?_第1张图片
拿pool-1-thread-1线程做例子,可以发现,每次pool-1-thread-1线程都会取到它处理的前一个请求所设置的值,但其实这是不同的请求,只是由同一个线程做处理而已,有点数据污染的意思了,一些特定的业务逻辑下就很有可能出错。

调用remove的demo:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadLocalDemo {

    private static ExecutorService executorService = Executors.newFixedThreadPool(3);
    private static ThreadLocal<String> threadLocal = new ThreadLocal();

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            int j = i + 1;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "---设值前threadLocal=" + threadLocal.get());
                    threadLocal.set(Thread.currentThread().getName() + " and 第" + j + "个请求");
                    System.out.println(Thread.currentThread().getName() + "---设值后threadLocal=" + threadLocal.get());
                    threadLocal.remove();
                }
            });
        }
        executorService.shutdown();
    }
}

运行结果:
使用完ThreadLocal不调用remove方法会导致业务逻辑出错?_第2张图片

从这次运行结果可以发现,十个请求之间的数据不再有交叉污染了,同一个线程处理的不同请求,不会再得到上一个请求所使用的值。

总结

因为ThreadLocal就是个map,是以线程id为key的,如果线程不复用还好说,每个请求都是不同的线程id,那么就可以避免以上的问题,但是如果是线程池和ThreadLocal配合使用,那么就需要小心使用了,及时的调用remove方法,防止数据污染导致业务逻辑出现问题。

你可能感兴趣的:(Java并发编程)