美文网首页
Java ThreadLocal 的用法

Java ThreadLocal 的用法

作者: oO白眉大虾Oo | 来源:发表于2019-07-31 20:13 被阅读0次

    前言

    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
    

    相关文章

      网友评论

          本文标题:Java ThreadLocal 的用法

          本文链接:https://www.haomeiwen.com/subject/qkgfgftx.html