ThreadLocal
使用场景:在需要定义一个全局变量时,多个线程访问,不希望线程之间互相影响。比如存放token信息和用户信息等
作用:线程隔离,提供线程全局变量。
原理:ThreadlLocal类中有ThreadLocalMap类型的ThreadLocals属性,ThreadLocals中的key就是当前线程对象,value是set的值。如下图就是一个关系结构示意图。在新建一个线程时,会新new 一个ThreadLocalMap,即给线程提供一个全局变量的副本,从而避免线程间的相互影响。
主要的方法:get(),set(),initialValue()
下面用代码实现看看threadLocal的作用:
代码01:两个线程进行对应全局变量num的修改,每个线程进行三次操作。
public class Test02 {
private static int num=0;
public synchronized int getNextNum(){
num++;
return num;
}
public static void main(String[] args) {
Test02 test02 = new Test02();
Thread thread = new MyThread(test02);
Thread thread1 = new MyThread(test02);
thread.start();
thread1.start();
}
public static class MyThread extends Thread {
private Test02 m;
public MyThread(Test02 m) {
this.m = m;
}
@Override
public void run() {
for(int i=0;i<3;i++) {
System.out.println(Thread.currentThread().getName()+":"+m.getNextNum());
}
}
}
}
查看运行结果:全局变量num最大值为6,线程间相互影响。
代码02:同样的全局变量,但是用ThreadLocal进行的初始化。两个线程进行修改。
public class Test03 {
public static ThreadLocal<Integer> num = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 0;
};
};
public synchronized int getNextNum(){
num.set(num.get()+1);
return num.get();
}
public static void main(String[] args) {
Test03 test03 = new Test03();
Thread thread = new MyThread(test03);
Thread thread1 = new MyThread(test03);
thread.start();
thread1.start();
}
public static class MyThread extends Thread {
private Test03 m;
public MyThread(Test03 m) {
this.m = m;
}
@Override
public void run() {
for(int i=0;i<3;i++) {
System.out.println(Thread.currentThread().getName()+":"+m.getNextNum());
}
}
}
}
结果:全局变量num的最大值为3,并且两个线程的最大值都为3,可以看到两个线程间是没有互相影响的。
InheritableThreadLocal
是ThreadLocal的子类。重写了ThreadLocal中的三个方法:childValue(),getMap(),createMap()。
InheritableThreadLocal有一个ThreadLocalMap 类型的inheritableThreadLocals 属性
与ThreadLocal的主要区别是:ThreadLocal主线程定义的变量,子线程无法继承,如果子线程没有定义变量值,默认会是null;InheritableThreadLocal主线程定义的变量,如果子线程没有定义变量,会默认取主线程定义的值。