ThreaLocal的使用及其原理

  ThreadLocal用于在一个线程中存入一个变量,这样,在此线程执行到其它地方时,就可以在通过ThreadLocal取出此变量,ThreadLocal在多线程开发中会经常使用到。

一、ThreaLocal的使用:

 1、使用ThreaLocal写入一个"data"字符串:

  1.1、在类中声明一个类变量:
  private ThreadLocal<String> threadLocal = new ThreadLocal<>();
  1.2、设置变量:
  threadLocal.set("data");

 2、使用ThreaLocal获取存入的字符串:

  threadLocal.get();


二、示例代码:

  下面的示例代码为四个线程执行一个Runnable对象,Runnable为每个线程随机写入"A"或者"B",然后在读取每个线程的数据,使用ThreadLocal,能保证每个线程前后存取数据的一致性:

Runnable:

public class ThreadLocalRunnable implements Runnable {

    private ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public void run() {

        double random = Math.random();
        if (random < 0.5) {
            threadLocal.set("A");

            System.out.println("线程名称为" + Thread.currentThread().getName() + "-----保留了A");
        } else {
            threadLocal.set("B");

            System.out.println("线程名称为" + Thread.currentThread().getName() + "-----保留了B");
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("线程名称为" + Thread.currentThread().getName() + "-----保留的数据为" + threadLocal.get());
    }

}
Thread:

public class ThreadLocalTest {

    public static void main(String[] args) {

        ThreadLocalRunnable localRunnable = new ThreadLocalRunnable();

        Thread thread1 = new Thread(localRunnable);
        thread1.setName("thread1");
        Thread thread2 = new Thread(localRunnable);
        thread2.setName("thread2");
        Thread thread3 = new Thread(localRunnable);
        thread3.setName("thread3");
        Thread thread4 = new Thread(localRunnable);
        thread4.setName("thread4");


        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }

}
测试的执行结果:

线程名称为thread1-----保留了A
线程名称为thread2-----保留了B
线程名称为thread3-----保留了B
线程名称为thread4-----保留了A
线程名称为thread2-----保留的数据为B
线程名称为thread4-----保留的数据为A
线程名称为thread1-----保留的数据为A
线程名称为thread3-----保留的数据为B
可以看出,每个线程存取的数据保持了一致,比如thread1与thread4前后都为A,而thread2与thread3前后都为B。

三、原理:

 在java中,每个线程对应一个Thread对象,而在Thread中,有这样一个变量:

 /* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
 ThreadLocal.ThreadLocalMap threadLocals = null;

 ThreadLocalMap类,可以看成是以 ThreadLocal对象为key,Object为value的map,所以可能大家想到了,每次使用threadLocal对象去存一个Object时,实际上是以这个threadLocal对象为key,value为对应Object存储到当前线程的ThreadLocalMap中,取出时,在从当前线程的ThreadLocalMap中以threadLocal对象为key取出对应Object。我们可以看看ThreadLocal的set(Object)与get()的源码:

 1、set(Object):

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

  可以看出,先通过Thread.currentThread()得到当前线程,然后得到当前的map,如果map为空,创建一个新的map,并将key-value直接传入,如果map不为空,直接将key-value传入,注意,key都为自己,即ThreadLocal的对象。

 2、get():

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

 get()方法就简单一些了,得到当前线程的map,然后得到以自己为key的对应value。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值