ThreadLocal

  ThreadLocal:看到这个单词,大家应该就猜到了,跟线程有关系。在讲之前我们先来看一段简单的代码:

public class ThreadLocalTest {

    public static void main(String[] args) {
        final Demo demo = new ThreadLocalTest().new Demo();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.setNum(1);
                try {
                    Thread.sleep(100);
                }catch (Exception e){

                }
                demo.getNum("thread1");
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.setNum(2);
                try {
                    Thread.sleep(100);
                }catch (Exception e){

                }
                demo.getNum("thread2");
            }
        });
        thread1.start();
        thread2.start();
    }

    class Demo{
        private int num;
        public void setNum(int num){
            this.num = num;
        }

        public void getNum(String name){
            System.out.println(name+":num=="+num);
        }
    }
}

这个是模拟两个线程同时去操作一个共享变量,很容易看出来,返回的数据肯定是一致的,结果:

那么现在如果要求,每个线程打印出来的值一定是自己设置的值,我们可以怎么做呢?

那下面我们来修改一下这个代码:

public class ThreadLocalTest {

    public static void main(String[] args) {
        final Demo demo = new ThreadLocalTest().new Demo();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.setNum(1);
                try {
                    Thread.sleep(100);
                }catch (Exception e){

                }
                demo.getNum("thread1");
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.setNum(2);
                try {
                    Thread.sleep(100);
                }catch (Exception e){

                }
                demo.getNum("thread2");
            }
        });
        thread1.start();
        thread2.start();
    }

    class Demo{
        private ThreadLocal<Integer> num = new ThreadLocal<>();
        public void setNum(int num){
            this.num.set(num);
        }

        public void getNum(String name){
            System.out.println(name+":num=="+num.get());
        }
    }
}

在这里我们把num定义为ThreadLocal对象,然后我们开一看一下执行结果:

从结果可以看出来,每个线程打印出来的结果都是当前本线程自己修改过的值,多个线程之间相互没有影响。

由此可以看出ThreadLocal就是使共享变量在每个线程中的操作相互不影响的作用。那么它是如何做到这一点的呢?我们下面来深入了解一下它的源码实现:

我们先来看一下它的set()方法:

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

解析一下:1.首先我们要获取到当前操作的线程

                2.获取当前线程的ThreadLocalMap类型的一个map对象,下面我们会说到这个ThreadLocalMap

                3.如果map存在,这把当前的值放进去,可以看到这里key放置的是当前操作的ThreadLocal对象,值就是当前设置的值

               4.如果map不存在,创建map并设置值

下面我们来看一下第二步:获取map的值

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

这里我们可以看见,传进来的参数是当前的线程对象T,这个map其实就是当前线程对象的变量:threadLocals

ThreadLocal.ThreadLocalMap threadLocals = null;

大家应该看到了,这个threadLocals就是ThreadLocal类里的ThreadLocalMap类型的一个对象。

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

这里我们看到这里主要是给当前线程的threadlocals变量初始化,并且赋值。

下面我们看一下get()方法:

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

解析一下:1.首先我们要获取到当前操作的线程

                2.获取当前线程的ThreadLocalMap类型的一个map对象,下面我们会说到这个ThreadLocalMap

                3.如果map存在,这把当前的值放进去,可以看到这里key放置的是当前操作的ThreadLocal对象,值就是当前设置的值

               4.如果map不存在,创建map并设置值

我们看一下setInitialValue方法,这里是初始化了以个空值进去。

private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

总结:ThreadLocal为什么可以隔离数据,主要是因为他的内部是一个ThreadLocalMap(实现了Map功能),这里的key存储的是每一个线程,值是当前线程里设置的值,所以每个线程获取到的都是当前自己的数据,与其他线程是隔离的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值