@[toc]
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需要回滚