多线程--ThreadLocal

1.什么是Threadlocal

ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量。
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

static final ThreadLocal<T> sThreadLocal = new ThreadLocal<T>();
sThreadLocal.set()
sThreadLocal.get()

threadlocal而是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据,官方解释如下。

/**

  • This class provides thread-local variables. These variables differ from
  • their normal counterparts in that each thread that accesses one (via its
  • {@code get} or {@code set} method) has its own, independently initialized
  • copy of the variable. {@code ThreadLocal} instances are typically private
  • static fields in classes that wish to associate state with a thread (e.g.,
  • a user ID or Transaction ID).
    */

大致意思就是ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。

做个不恰当的比喻,从表面上看ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。

案例如下

package com.yxl.demo.ThreadTest;

public class Test6 {

    public static void main(String[] args) {
        Res res=new Res();
        Thread thread = new Thread(res,"6666");
        Thread thread2 = new Thread(res,"777");
        thread.start();
        thread2.start();

    }


}

class Res implements Runnable {
    public  static Integer count = 0;

    public  Integer getNumber(){

        return count++;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3 ; i++) {
            System.out.println(Thread.currentThread().getName()+ ","+getNumber());
        }
    }
}

运行结果 :发现都是共享变量,现在需要让 res 变成局部变量
在这里插入图片描述

需要变成局部变量,解决方案 使用Threadlocal

package com.yxl.demo.ThreadTest;

public class Test6 {

    public static void main(String[] args) {
        Res test6=new Res();
        Thread thread = new Thread(test6,"6666");
        Thread thread2 = new Thread(test6,"777");
        thread.start();
        thread2.start();

    }


}

class Res implements Runnable {
    //public  static Integer count = 0;

    //创建ThreadLocal
    public static ThreadLocal<Integer> threadLocal =new ThreadLocal<Integer>(){
        protected Integer initialValue(){
            return  0;
        }
    };

    public  Integer getNumber(){
        int count = threadLocal.get()+1;
        threadLocal.set(count);
        return count;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3 ; i++) {
            System.out.println(Thread.currentThread().getName()+ ","+getNumber());
        }
    }
}

运行结果:

在这里插入图片描述

ThreadLoca实现原理

ThreadLoca通过map集合
Map.put(“当前线程”,值);

底层 get方法


public T get() {
		//获取线程
        Thread t = Thread.currentThread();
        //其中getMap(t)返回的就上当前线程的threadlocals
        ThreadLocalMap map = getMap(t);
        //判断map是否null
        //然后根据当前ThreadLocal实例对象作为key获取ThreadLocalMap中的value,如果首次进来这调用setInitialValue()
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

底层 set 方法:(同get)

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

ThreadLocal 应用场景:

1.用户登录,从token那用户唯一标识,方到threadLocal里边。在业务层就能随时用了
2.事务控制 ,哪条线程执行哪条sql需要回滚

发布了18 篇原创文章 · 获赞 19 · 访问量 1023

猜你喜欢

转载自blog.csdn.net/qq_41977838/article/details/105766305