美文网首页
ThreadLocal 解析

ThreadLocal 解析

作者: _一叶孤帆 | 来源:发表于2021-02-02 10:57 被阅读0次

ThreadLocal

每个线程都有一个 ThreadLocal 变量的副本,实现了线程的隔离。

使用

    //构建 ThreadLocal 并制定初始值。
    public ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<Integer>(){

        //重写此方法来给一个默认值。
        @Override
        protected Integer initialValue() {
            return 1;
        }
    };
    //构建 ThreadLocal 并制定初始值。
    public ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<Integer>();

实现 runnable 接口来创建一个线程类,并在 run() 中打印 threadlocal 加线程 id 的值

    /**
     * 创建线程
     */
    public class TestThread implements Runnable {

        int id;
        public TestThread(int id){
            this.id = id;
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "启动线程");
            Integer s = 1 + id;
            integerThreadLocal.set(s);
            System.out.println(Thread.currentThread().getName() + ":" + integerThreadLocal.get());
            //如果不调用 remove 会发生内存泄露
            integerThreadLocal.remove();
        }
    }

利用一个方法来启动三个线程

    /**
     * 启动线程
     */
    public void startThreadArray(){
        Thread[] threads = new Thread[3];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new TestThread(i));
        }

        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
    }

进行测试

    public static void main(String[] args) {
    // write your code here
        Main m = new Main();
        m.startThreadArray();
    }
}

输出结果:

Thread-0启动线程
Thread-1启动线程
Thread-2启动线程
Thread-0:1
Thread-2:3
Thread-1:2

分析

我们 Main 类有一个变量 integerThreadLocal, 这个变量在三个线程中修改。正常情况下会出现线程安全问题。但是看结果是没有的。

这个时候,我们需要看 threadLoaclset方法

integerThreadLocal.set(s);

我们看一下源码
ThreadLocal

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }

这里有一个 ThreadLocalMap, 然后调用了它的get方法,我们看一下get方法

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

可以看出,它又调用了ThreadthreadLocals.

可以看出在Thread中有一个ThreadLocalMap的成员变量

ThreadLocal.ThreadLocalMap threadLocals = null;

所以我们在 ThreadLocal 中的set方法其实也就是调用的Thread中的threadLocalscreateMap 也是给线程的
threadLocals进行初始化。

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

然后再map.set(this, value) 中,将 ThreadLocal为键,传入的 value 为值,将其保存在了线程中的 threadLocals 里。所以其实每个线程都有一个 ThreadLocal 对应的 value,实现了线程隔离。

同理,ThreadLocalget方法也是取Thread 中的 threadLocals

    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();
    }

ThreadLocal 引发的内存泄露

image.png

上面这张图详细的揭示了ThreadLocal和Thread以及ThreadLocalMap三者的关系。

1、Thread中有一个map,就是ThreadLocalMap
2、ThreadLocalMap的key是ThreadLocal,值是我们自己设定的。
3、ThreadLocal是一个弱引用,当为null或者触发GC时,会被当成垃圾回收
4、突然我们ThreadLocal要被垃圾回收器回收了,但是此时我们的ThreadLocalMap生命周期和Thread的一样,它不会回收,这时候就出现了一个现象。那就是ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。

解决办法:使用完ThreadLocal后,执行remove操作,避免出现内存泄露的情况。

ThreadLocalMap 的开放寻址法

后面补~

代码

https://github.com/ios-yifan/threadlocal

参考

https://baijiahao.baidu.com/s?id=1653790035315010634&wfr=spider&for=pc
https://www.jianshu.com/p/3c5d7f09dfbd

相关文章

  • 线程中的ThreadLocal

    ThreadLocal解析

  • JDK ThreadLocal解析

    Java ThreadLocal解析 ThreadLocal 线程本地变量, 线程私有, 在 Thread 类中用...

  • ThreadLocal 深度解析

    一.对ThreadLocal的理解二.深入解析ThreadLocal类三.ThreadLocal的应用场景 对Th...

  • ThreadLocal解析

    前言 刚看过EventBus和AndroidEventBus的源码, 发现里面都有用到ThreadLocal, 那...

  • ThreadLocal解析

    前言 在各大公司招聘笔试和面试题题中,都遇到了很多ThreadLocal的问题,最近博主在面试的时候也被两次问到过...

  • ThreadLocal解析

    一、简介 首先我们需要知道Thread.currentThread()获取当前线程对象,同一个线程每次获取的都是同...

  • ThreadLocal解析

    前言 我们都知道ThreadLocal用于为每个线程存储自己的变量值,起到线程间隔离的作用,那么它到底是怎么运行的...

  • ThreadLocal解析

    ThreadLocal,顾名思义,肯定是与Thread类有关系的,所以先从Thread类入手。 Thread和Th...

  • ThreadLocal解析

    原理 产生线程安全问题的根源在于多线程之间的数据共享。如果没有数据共享,就没有多线程并发安全问题。ThreadLo...

  • ThreadLocal解析

    我们都知道,ThreadLocal在多线程中使用,即多线程共享一个变量,正常情况下线程安全。其主要原理是内部持有的...

网友评论

      本文标题:ThreadLocal 解析

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