2020-04-05 ThreadLocal一探究竟


package hxy.bytecode.thread.threadlocal;

public class ThreadLocalDemo {
    static class ThreadA implements Runnable {
        private ThreadLocal<String> threadLocal;

        public ThreadA(ThreadLocal<String> threadLocal) {
            this.threadLocal = threadLocal;
        }

        @Override
        public void run() {
            threadLocal.set("A");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


            System.out.println("ThreadA " + threadLocal.get() + "\thashCode:" + threadLocal.hashCode());
        }
    }

    static class ThreadB implements Runnable {
        private ThreadLocal<String> threadLocal;

        public ThreadB(ThreadLocal<String> threadLocal) {
            this.threadLocal = threadLocal;
        }

        @Override
        public void run() {
            threadLocal.set("B");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("ThreadB " + threadLocal.get() + "\thashCode:" + threadLocal.hashCode());
        }
    }

    public static void main(String[] args) {
        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        threadLocal.set("测试");
//        上面新建了一个实例,下面传入多个线程,但是每个线程都复制了一个副本
        new Thread(new ThreadA(threadLocal)).start();
        new Thread(new ThreadB(threadLocal)).start();
        new Thread(new ThreadB(threadLocal)).start();

        System.out.println(Thread.currentThread().getName() + threadLocal.get() + "\thashCode:" + threadLocal.hashCode());

    }

}

上面代码可以看出来,所有线程的对象应该都是使用了main方法新建的ThreadLocal的实例,但是传入到各个线程之后竟然全部不一样了。相当于每个线程都拥有了实例的副本,且各不相关,特殊之处就在本来就是一个对象,但是赋值到各个线程之后,竟然不是原来的。从下面打印的hashCode发现,各个线程接受的实例确实是main方法创建的同一个,但是为啥效果却不一样了。

image.png

进入ThreadLocal的set方法一探究竟。

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

    }

从上面可以看出来端倪了。系统维护了个全局变量的map,可以依据线程放对象线程的map值,然后再依据线程去取出该线程的map对象就好了。

推荐阅读更多精彩内容