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
上一篇下一篇

猜你喜欢

热点阅读