多线程-ThreadLocal

更新时间:2020-05-28 11:07:52点击次数:285次
ThreadLocal
早在JDK 1.2 的版本中就提供 java.lang.ThreadLocal .

ThreadLocal为解决多个线程并发问题提供了一种新的思路。

是一个工具类,可以很简洁的编写出多线程

ThreadLocal 很容易我们理解为本地线程,ThreadLocal并不是一个线程,而是线程中的一个局部变量。

ThreadLocal 为每个线程提供独立的变量副本,每个线程都可以改变自己的副本,不会影响其它线程多多对应的副本

ThreadLocal使用场景
多个线程共享同一个数据,会引发线程安全问题,虽然可以使用synchronized 和 Lock

避免安全问题,但难免多个线程存在资源争夺问题。

那么如何解决线程下效率低问题呢?

让每个线程都是用自己独立的数据,不和别的线程共享,就可以多个线程避免资源争夺问题

实例:

public class Test2 {
    public static void main(String[] args) {

       ThreadLocal<Integer> t = new ThreadLocal<>();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                t.set(10);//10
                System.out.println(t.get());
            }
        });
        t1.start();


        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                /*每个线程独立的数据 不共享*/
                System.out.println(t.get());//null
                t.set(10);
                System.out.println(t.get());//10
            }
        });
        t2.start();
    }
}

ThreadLocal 存储分析
ThreadLocal只是操作本地线程隔离的数据的工具类,它本身并不是存储数据的,真正存储数据的是线程Thread对象本身。

通过源码我们可看到Thread类中有存在的ThradLocade

Thread部分源码:

 /* 属于这个线程的ThreadLocal值。这个Map保留了下来
通过ThreadLocal类。 */
ThreadLocal.ThreadLocalMap threadLocals = null;

查看ThreadLocal类 get 和 set 方法发现:

使用set 方法时,是获取当前线程,然后获取当前线程的 threadLocals,然后将value赋值给当前线程的threadLocals

  /**
*设置此线程本地变量的当前线程的副本
*到指定的值。大多数子类将不需要这样做
*重写此方法,仅依赖于{@link #initialValue}
*方法设置线程局部变量的值。
*要存储在当前线程的副本中的值
*这个线程局部。
  */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
             createMap(t, value);
    }    
        

getMap源码

/ * *
* 获取与ThreadLocal关联的映射。覆盖在
* InheritableThreadLocal。
*
* @param t当前线程
* @返回Map
* /
ThreadLocalMap getMap(Thread t) {
     return t.threadLocals;
}

使用ThradLocal类get方法时,获取当前线程,然后获取当前线程副本的value

/ * *
*返回当前线程的这个副本的值
*线程局部变量。如果变量没有值
*当前线程,它首先被初始化为返回的值
*通过调用{@link #initialValue}方法。
*
* @返回当前线程的线程本地值
* /
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 内部类 ThreadLocalMap源码

/ * *
* ThreadLocalMap是一个定制的哈希映射,只适用于
*维护线程本地值。不导出操作
*在ThreadLocal类的外部。类是包私有的
*允许在类线程中声明字段。帮助处理
*非常大且长期存在的用法,哈希表条目使用
*键的弱引用。但是,因为引用队列不是
*已使用的陈旧条目保证仅在以下情况下被删除
*这个表开始没有空间了。
* /
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
       /**与这个ThreadLocal关联的值*/
      Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
      value = v;
        }
  }
}

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息