IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> JDK8 ThreadLocal源码 -> 正文阅读

[移动开发]JDK8 ThreadLocal源码

package java.lang;
import java.lang.ref.*;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

public class ThreadLocal<T> {
    /**
     * 初始值为0
     */
    private final int threadLocalHashCode = nextHashCode();

    /**
     * hash值,初始为0
     */
    private static AtomicInteger nextHashCode =
            new AtomicInteger();

    /**
     * 值为2^32*0.618,
     */
    private static final int HASH_INCREMENT = 0x61c88647;

    /**
     * 求下一个hashcode,每次加HASH_INCREMENT,冲突少
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

    /**
     * 初始化值,好像可以重写
     */
    protected T initialValue() {
        return null;
    }

    /**
     * 带初始值
     */
    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
        return new SuppliedThreadLocal<>(supplier);
    }

    /**
     * 默认构造方法
     */
    public ThreadLocal() {
    }

    /**
     * 根据线程获取映射结果副本,线程隔离
     */
    public T get() {
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        // 如果当前线程的ThreadLocalMap不为空
        if (map != null) {
            // 到ThreadLocalMap中去找当前线程对应的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            // 如果找到的位置的元素不为null,则返回结果
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        // 如果当前线程的ThreadLocalMap为null或者当前线程在数组中映射的位置的元素为null,设置并初始化,返回初始值
        return setInitialValue();
    }

    /**
     * 将当前线程对应value设置为初始值
     */
    private T setInitialValue() {
        // 获取初始值,默认为null
        T value = initialValue();
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        // 如果map不为空,设置当前线程的value为初始值
        if (map != null)
            map.set(this, value);
        // 否则创建map,并且设置当前线程的value为初始值
        else
            createMap(t, value);
        // 返回结果
        return value;
    }

    /**
     * 设置值
     */
    public void set(T value) {
        // 获取当前线程的ThreadLocalMap
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        // 如果map不为空,就set
        if (map != null)
            map.set(this, value);
        // 否则创建map并set
        else
            createMap(t, value);
    }

    /**
     * 删除当前线程的值
     */
    public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread());
        if (m != null)
            m.remove(this);
    }

    /**
     * 获取该线程的ThreadLocalMap
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    /**
     * 为当前线程创建ThreadLocalMap
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    /**
     * 父子继承,将父线程的变量交给子线程
     */
    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }

    T childValue(T parentValue) {
        throw new UnsupportedOperationException();
    }

    /**
     * 用于扩展ThreadLocal,可以重写初始值
     */
    static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {

        private final Supplier<? extends T> supplier;

        SuppliedThreadLocal(Supplier<? extends T> supplier) {
            this.supplier = Objects.requireNonNull(supplier);
        }

        @Override
        protected T initialValue() {
            return supplier.get();
        }
    }

    /**
     * 使用结束后需要删掉键值对
     */
    static class ThreadLocalMap {

        /**
         * 底层是数组,元素是Entry类型,继承了虚引用,可能会被垃圾回收
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            // 该元素的值
            Object value;

            /**
             * 构造,记录结点的key和value值
             */
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * 默认初始化容量,必须是2的幂
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * 底层是数组,可以扩容
         */
        private Entry[] table;

        /**
         * 数组元素个数
         */
        private int size = 0;

        /**
         * 扩容阈值
         */
        private int threshold; // Default to 0

        /**
         * S默认负载因子为2/3 ,当长度超过当前容量的2/3时会扩容
         */
        private void setThreshold(int len) {
            threshold = len * 2 / 3;
        }

        /**
         * 查找下一个位置
         * 每次位置+1,如果越界则变成0
         */
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }

        /**
         * 查找前一个位置
         * 每次位置-1,如果越界变为len-1
         */
        private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
        }

        /**
         * 构造,线程对应value值
         */
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            // 创建数组
            table = new Entry[INITIAL_CAPACITY];
            // 根据线程的hash值 ,获取线程在数组中下标
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            // 初始化该位置元素
            table[i] = new Entry(firstKey, firstValue);
            // 容量设置为1
            size = 1;
            // 设置扩容阈值
            setThreshold(INITIAL_CAPACITY);
        }

        /**
         * 根据新的ThreadLocalMap构造自己的Map
         */
        private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];

            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }

        /**
         * 根据key获取数组元素
         */
        private Entry getEntry(ThreadLocal<?> key) {
            // 根据key的hashcode计算其在元素的位置
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            // 如果该位置有元素并且其等于key,就返回该元素
            if (e != null && e.get() == key)
                return e;
            // 遍历之后的元素并判断是否可以返回
            else
                return getEntryAfterMiss(key, i, e);
        }

        /**
         * 当getEntry方法里,根据key直接计算的位置
         * 该位置如果是null,则直接返回null
         * 如果该位置不为null,则计算下一位置,直到找到对应的元素或者为null
         */
        private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;

            while (e != null) {
                // 获取当前节点的ThreadLocal
                ThreadLocal<?> k = e.get();
                // 如果是这个元素,则返回
                if (k == key)
                    return e;
                // 如果这个元素是空,清除旧元素
                if (k == null)
                    expungeStaleEntry(i);
                // 如果元素不为空且不相等,计算下一个位置
                else
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }

        /**
         * 设置key对应的value
         */
        private void set(ThreadLocal<?> key, Object value) {
            // 计算key的位置
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
                // 获取直接计算位置的元素的key
                ThreadLocal<?> k = e.get();
                // 如果该位置的key等于当前key,覆盖并返回
                if (k == key) {
                    e.value = value;
                    return;
                }
                // 如果该位置的key为空,交换过过期数据
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            // 如果数组里没有该key,那么新建一个放进去
            tab[i] = new Entry(key, value);
            int sz = ++size;
            // 如果没有可回收的元素并且数组元素个数大于等于阈值,则重hash、扩容
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

        /**
         * 删除代表这个key的元素
         */
        private void remove(ThreadLocal<?> key) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                if (e.get() == key) {
                    e.clear();
                    expungeStaleEntry(i);
                    return;
                }
            }
        }

        /**
         *
         * @param key 当前key已经过期
         * @param value 应当被设置的值
         * @param staleSlot key所在区段的某一下标
         */
        private void replaceStaleEntry(ThreadLocal<?> key, Object value,
                                       int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;
            Entry e;

            // staleSlot位置的元素的key 是null,说明是脏数据,会被删除
            int slotToExpunge = staleSlot;
            // 从当前位置开始往前找,记录最前的一个数组中元素不为null且key为null的位置
            for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len))
                // 但是这个位置的元素的key为null,标记这个位置
                if (e.get() == null)
                    slotToExpunge = i;

            // 从当前位置向后找
            for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
                ThreadLocal<?> k = e.get();

                // 如果key等于当前key,则赋值并交换
                if (k == key) {
                    // e是当前位置的元素,赋值value
                    e.value = value;
                    // key所在元素变成了过期元素
                    tab[i] = tab[staleSlot];
                    // 过期元素的位置变成了key所对应的元素
                    tab[staleSlot] = e;

                    // 如果staleSlot前面的元素为null,则slotToExpunge=当前位置
                    if (slotToExpunge == staleSlot)
                        slotToExpunge = i;
                    // 清除过期数据
                    cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
                    return;
                }

                // 若果当前位置已过期并且当前位置的前元素为null,则slotToExpunge=当前位置
                if (k == null && slotToExpunge == staleSlot)
                    slotToExpunge = i;
            }

            // 如果没找到key,则创建一个新节点
            tab[staleSlot].value = null;
            tab[staleSlot] = new Entry(key, value);

            // 如果有过期的结点,就清除过期结点
            if (slotToExpunge != staleSlot)
                cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
        }

        /**
         * 清除旧节点,并重新计算该节点之后节点的位置
         * 返回位置的元素为null
         */
        private int expungeStaleEntry(int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;

            // 删掉这个位置的元素
            tab[staleSlot].value = null;
            tab[staleSlot] = null;
            size--;

            Entry e;
            int i;
            // 从当前位置向后遍历,直到该元素为null。如果元素的key被回收则抛弃,否则重计算元素其在数组中位置
            // 从实际计算位置一直往后找,因为之前元素被删,所以之后的元素要重新计算位置
            for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
                ThreadLocal<?> k = e.get();
                // 如果下个位置的key为null,则删除这个元素
                if (k == null) {
                    e.value = null;
                    tab[i] = null;
                    size--;
                    // 否则计算这个key的位置,如果计算位置和当前位置不同,则删除这个元素
                } else {
                    int h = k.threadLocalHashCode & (len - 1);
                    if (h != i) {
                        tab[i] = null;
                        // 一直向后找,直到有位置并放进去
                        while (tab[h] != null)
                            h = nextIndex(h, len);
                        tab[h] = e;
                    }
                }
            }
            return i;
        }

        /**
         * 清除一些过期结点
         * 最少循环log n次
         */
        private boolean cleanSomeSlots(int i, int n) {
            boolean removed = false;
            Entry[] tab = table;
            int len = tab.length;
            do {
                i = nextIndex(i, len);
                Entry e = tab[i];
                if (e != null && e.get() == null) {
                    n = len;
                    removed = true;
                    i = expungeStaleEntry(i);
                }
            } while ( (n >>>= 1) != 0);
            return removed;
        }

        /**
         * 重哈希
         * 1. 清除过期元素
         * 2. 如果超过3/4阈值,需要扩容
         */
        private void rehash() {
            // 清除所有过期元素
            expungeStaleEntries();

            // Use lower threshold for doubling to avoid hysteresis
            if (size >= threshold - threshold / 4)
                resize();
        }

        /**
         * 扩容
         * 1. 数组长度变两倍
         * 2. 如果key已经被回收,则不复制
         * 3. 否则重新计算在新数组中位置,冲突则+1
         * 4. 阈值、元素个数重计算
         */
        private void resize() {
            Entry[] oldTab = table;
            int oldLen = oldTab.length;
            int newLen = oldLen * 2;
            Entry[] newTab = new Entry[newLen];
            int count = 0;

            for (int j = 0; j < oldLen; ++j) {
                Entry e = oldTab[j];
                if (e != null) {
                    ThreadLocal<?> k = e.get();
                    if (k == null) {
                        e.value = null; // Help the GC
                    } else {
                        int h = k.threadLocalHashCode & (newLen - 1);
                        while (newTab[h] != null)
                            h = nextIndex(h, newLen);
                        newTab[h] = e;
                        count++;
                    }
                }
            }

            setThreshold(newLen);
            size = count;
            table = newTab;
        }

        /**
         * 清除数组中所有过期的元素
         * 只要元素不为null且key为null就是过期
         */
        private void expungeStaleEntries() {
            Entry[] tab = table;
            int len = tab.length;
            for (int j = 0; j < len; j++) {
                Entry e = tab[j];
                if (e != null && e.get() == null)
                    expungeStaleEntry(j);
            }
        }
    }
}

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:02:21  更:2022-03-21 21:05:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:40:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码