• ThreadLocal


      ThreadLocal 是线程的局部变量, 是每一个线程所单独持有的,其他线程不能对其进行访问, 通常是类中的 private static 字段,是对该字段初始值的一个拷贝,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联

      我们知道有时候一个对象的变量会被多个线程所访问,这时就会有线程安全问题,当然我们可以使用synchorinized 关键字来为此变量加锁,进行同步处理,从而限制只能有一个线程来使用此变量,但是加锁会大大影响程序执行效率,此外我们还可以使用ThreadLocal来解决对某一个变量的访问冲突问题。

      当使用ThreadLocal维护变量的时候 为每一个使用该变量的线程提供一个独立的变量副本,即每个线程内部都会有一个该变量,这样同时多个线程访问该变量并不会彼此相互影响,因此他们使用的都是自己从内存中拷贝过来的变量的副本, 这样就不存在线程安全问题,也不会影响程序的执行性能。

      但是要注意,虽然ThreadLocal能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用ThreadLocal要大。

    ThreadLocal 方法使用详解

    ThreadLocal 的几个方法: ThreadLocal 可以存储任何类型的变量对象, get返回的是一个Object对象,但是我们可以通过泛型来制定存储对象的类型。

    public T get() { } // 用来获取ThreadLocal在当前线程中保存的变量副本
    public void set(T value) { } //set()用来设置当前线程中变量的副本
    public void remove() { } //remove()用来移除当前线程中变量的副本
    protected T initialValue() { } //initialValue()是一个protected方法,一般是用来在使用时进行重写的

      Thread 在内部是通过ThreadLocalMap来维护ThreadLocal变量表, 在Thread类中有一个threadLocals 变量,是ThreadLocalMap类型的,它就是为每一个线程来存储自身的ThreadLocal变量的, ThreadLocalMap是ThreadLocal类的一个内部类,这个Map里面的最小的存储单位是一个Entry, 它使用ThreadLocal作为key, 变量作为 value,这是因为在每一个线程里面,可能存在着多个ThreadLocal变量

      初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。 
    然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找

    ThreadLocal 的应用场景

      最常见的ThreadLocal使用场景为 
      用来解决 数据库连接、Session管理等。

    二、原理

    线程共享变量缓存如下:

      Thread.ThreadLocalMap<ThreadLocalObject>;

    1、Thread: 当前线程,可以通过Thread.currentThread()获取。

    2、ThreadLocal:我们的static ThreadLocal变量。

    3、Object: 当前线程共享变量。

      我们调用ThreadLocal.get方法时,实际上是从当前线程中获取ThreadLocalMap<ThreadLocal,Object>,然后根据当前ThreadLocal获取当前线程共享变量Object。

      ThreadLocal.set,ThreadLocal.remove实际上是同样的道理。

    这种存储结构的好处:

    1、线程死去的时候,线程共享变量ThreadLocalMap则销毁。

    2、ThreadLocalMap<ThreadLocal,Object>键值对数量为ThreadLocal的数量,一般来说ThreadLocal数量很少,相比在ThreadLocal中用Map<Thread, Object>键值对存储线程共享变量(Thread数量一般来说比ThreadLocal数量多),性能提高很多。 

    关于ThreadLocalMap<ThreadLocalObject>弱引用问题:

      当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMap<null,Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。

      虽然ThreadLocal的get,set方法可以清除ThreadLocalMap中key为null的value,但是get,set方法在内存泄露后并不会必然调用,所以为了防止此类情况的出现,我们有两种手段。

    1、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;

    2、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。

  • 相关阅读:
    我是如何用三小时搞出个赚钱产品的?
    搭建一个基于nuxt.js的项目
    栅格系统
    git使用
    通过JS获取屏幕高度,借助屏幕高度设置div的高度
    如何理解盒模型
    e.target.value 和 this 的区别
    组件化设计:弹窗的使用逻辑
    uni-app 入坑记
    MAC 系统快捷键
  • 原文地址:https://www.cnblogs.com/guanghe/p/9222147.html
Copyright © 2020-2023  润新知