日常记录——多线程与高并发—ThreadLocal概念、原理、使用、ThreadLocal和synchronized对比

一、概念

ThreadLocal:线程本地变量,以空间换时间的方式为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。可以理解为一个当前线程的map对象,key为当前ThreadLocal,value为存放的对象。

二、原理

1.set():ThreadLocal为当前线程存储对象方法,设置当前线程对应的线程局部变量ThreadLocal.ThreadLocalMap threadLocals的值。如果不存在则用创建一个,然后将hreadLocal为key,存放对象为value的ThreadLocalMap类型对象赋值给当前线程的threadLocals属性。

  public void set(T value) {
  		//当前线程
        Thread t = Thread.currentThread();
        //创建ThreadLocalMap getMap(t)为返回当前此线程有的threadLocals值  	
        //threadLocals  为当前线程的  成员变量   类型为ThreadLocal.ThreadLocalMap  
        //ThreadLocalMap  是一个类 内含一个类型为 Entry<k,v>结构对象 k 为当前ThreadLocal对象  v 为 要存储对象
        //就是返回当前线程的 一个 类型为  ThreadLocalMap 的属性
        ThreadLocalMap map = getMap(t);
        if (map != null)
        	//不为空 以当前的ThreadLocal对象 为 key ,要存储对象 为 value
        	//当前线程.threadLocals = <ThreadLocal,要存储对象>
            map.set(this, value);
        else
        	//为空  创建以当前线程.threadLocals = <ThreadLocal,要存储对象>赋值给当前线程的ThreadLocalMap 的属性
        	//t.threadLocals = new ThreadLocalMap(this, firstValue);
            createMap(t, value);
    }

2.get():ThreadLocal为当前线程过去对象方法,该方法返回当前线程所对应的线程局部变量。如果不存在则返回一个null。

public T get() {
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的threadLocals
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        	//获取当前threadLocals 的 Entry对象 Entry
        	//Entry的成员变量为 
        	//Object value;
        	//Entry的构造方法为
        	//Entry(ThreadLocal<?> k, Object v) {
            //    super(k);
            //    value = v;
            //}  
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                //e 不为空  获取存放的对象
                T result = (T)e.value;
                return result;
            }
        }
        //为当先线程初始化一个  threadLocals 并且存放的value 为 null  并返回null
        return setInitialValue();
    }

三、使用

public class ThreadLocalTest {

    public static void main(String[] args) {
        ThreadLocal<Person> threadLocal = new ThreadLocal<>();
        new Thread(() -> {
            threadLocal.set(new Person("李四"));
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadLocal.get().name);
        }).start();
        new Thread(() -> {
            threadLocal.set(new Person("张三"));
            System.out.println(threadLocal.get().name);
        }).start();
    }
}

class Person{

    String name;

    public Person(String name) {
        this.name = name;
    }

}

注意:spring的显式声明事务用到了ThreadLocal,因为一个事物内的增删改查是基于一个connection的,不可能每一次与数据交互都是一个新的connection,所以一个事物内用ThreadLocal存储了本次事物的connection。

四、ThreadLocal和synchronized对比

ThreadLocal:每个线程一个对象资源。
synchronized:多个线程竞争一个对象资源。
注意:ThreadLocal存储的对象不用时必须用remove()回收掉,否则有内存泄漏风险。

猜你喜欢

转载自blog.csdn.net/weixin_43001336/article/details/107170454