zoukankan      html  css  js  c++  java
  • java.lang.ThreadLocal源码分析

    ThreadLocal类提供线程本地变量,为变量在每个线程创建一个副本,每个线程可以访问自己内部的副本变量。

    比如,有这样一个需求,需要为每个线程创建一个独一无二的标识,这个标识在第一次调用ThreadId.get()的时候生成,在随后的调用中不会再改变。

    public class ThreadId {
        private static final AtomicInteger nextId = new AtomicInteger(0);
        
        private static final ThreadLocal<Integer> threadId =
                new ThreadLocal<Integer>() {
                    @Override
                    protected Integer initialValue() {
                        return nextId.getAndIncrement();
                    }
        };
        public static int get() {
            return threadId.get();
        }
    }

    类声明:

    public class ThreadLocal<T> {}

    实例变量和相关的一个方法:

    //用于ThreadLocalMap
    private final int threadLocalHashCode = nextHashCode();
    
    //下一个hash code,从0开始
    private static AtomicInteger nextHashCode = new AtomicInteger();
    
    //hash增量
    private static final int HASH_INCREMENT = 0x61c88647;
    
    //在获取下一个hash code
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

    构造方法:

    public ThreadLocal() {}

    重要的操作:

    //线程本地变量的初始化方法,访问修饰符为protected是为了让程序员可以覆盖这个方法,默认是返回null,也就是说默认的线程本地变量值为null
    protected T initialValue() {
        return null;
    }

    get操作

    //获取当前线程的本地变量
    public T get() {
        Thread t = Thread.currentThread();//得到当前的线程
        ThreadLocalMap map = getMap(t);//根据当前线程获得一个ThreadLocalMap
        if (map != null) {//如果不为空
            ThreadLocalMap.Entry e = map.getEntry(this);//根据当前对象获得Entry
            if (e != null) {//如果本地变量存在,返回值
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
            }
        }
        //否则调用setInitialValue方法
        return setInitialValue();
    }

    getMap方法

    //返回当前线程的threadLocals变量
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    threadLocals的声明

    //其实就是一个ThreadLocalMap类型的变量
    ThreadLocal.ThreadLocalMap threadLocals = null;

    ThreadLocalMap

    //ThreadLocalMap里有Entry内部类,用于存放键值对
    static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
    
            Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
        .....以下省略
    }

    setInitialValue方法

    private T setInitialValue() {
        T value = initialValue();//调用initialValue方法,初始化本地变量的值,如果不覆盖该方法,返回null
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//根据当前线程获取ThreadLocalMap
        if (map != null)//如果map不为空
            map.set(this, value);//设置键值对
        else
            createMap(t, value);//否则创建map
         return value;
    }

    createMap方法

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    至此可以知道ThreadLocal如何为每个线程创建变量副本了,每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,存储以ThreadLocal为键,本地线程变量为值的键值对。

    remove操作

    //先获取当前线程的ThreadLocalMap,然后删除当前ThreadLocal对象
    public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread());
        if (m != null)
            m.remove(this);
    }
  • 相关阅读:
    一个网络传输框架——zeroMQ 调研笔记
    Node.js的cluster模块——Web后端多进程服务
    boost::spirit unicode 简用记录
    HTTP的长连接和短连接——Node上的测试
    MongoDB 驱动以及分布式集群读取优先级设置
    Lua知识备忘录
    MongoDB使用小结:一些常用操作分享
    此项目与Visual Studio的当前版本不兼容的报错
    @Controller和@RestController的区别
    SQLSERVER中计算某个字段中用分隔符分割的字符的个数
  • 原文地址:https://www.cnblogs.com/13jhzeng/p/5913762.html
Copyright © 2011-2022 走看看