代码改变世界

TPS04-J. 使用线程池时确保ThreadLocal变量每次都初始化

2017-01-04 09:57  微服务专家  阅读(749)  评论(0编辑  收藏  举报

线程池可以提供这种保障,一旦你的代码开始执行了,被分配来执行这个task的线程在执行完你的task之前不会做别的事情。

所以不用担心执行到一半被别的task改了 thread local 的变量。

由于线程重复使用所以你对thread local变量的修改都会保留下来

所以在使用前要把变量“重置”一下。 可以在每个task结尾做,也可以在开始做。

在结尾做的话需要放到finally里,确保执行

public final class Diary {
    // ...
    public static void removeDay() {
        days.remove();
    }
}

public final class DiaryPool {
    // ...
    public void doSomething1() {
        exec.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Diary.setDay(Day.FRIDAY);
                    diary.threadSpecificTask();
                } finally {
                    Diary.removeDay(); // 就是这里
                }
            }
        });
    }
// ...
}

 

另一个方法是在每次执行task之前做清理。

具体实现起来就是对executor进行扩展实现 beforeExecute 方法

class CustomThreadPoolExecutor extends ThreadPoolExecutor {
    public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
                                    long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    public void beforeExecute(Thread t, Runnable r) {
        if (t == null || r == null) {
            throw new NullPointerException();
        }
        Diary.setDay(Day.MONDAY);
        super.beforeExecute(t, r);
    }
}