一. 什么是变量的作用域?
常见的作用域:类变量>对象变量>函数变量
①.类变量:static修饰,这个类的所有对象共享同一个类变量,仅在类初始化的时候被初始化一次,有默认值
②.全局变量:非static的普通成员属性,每一个对象都拥有自己的对象变量,每次new对象的时候被初始化,有默认值
③.局部变量:函数内部的变量,仅在执行该方法时存在于栈空间,无默认值,不初始化编译不通过
在多线程应用中,我们需要对一些共享的类变量和对象变量进行同步互斥以保证多线程条件下的线程安全,如果一个变量仅存在自己的线程中,即作用域为线程内,那么就可以避免线程同步的问题了。ThreadLocal和InheritableThreadLocal类型的变量就是这样的存在。
二. ThreadLocal和InheritableThreadLocal变量的作用域
//Thread类的普通成员变量
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class.
* 线程本地变量,作用域为一个线程内
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
* 可继承的线程本地变量,新建子线程的时候浮现出的inheritableThreadLocals 被传递给了子线程
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/**
* 〈线程本地变量的测试〉
*
* @author 李子
* @create 2019/1/27 12:54
* @since 1.0.0
*/
public class ThreadLocalTest {
public String string = new String();//全局变量
public ThreadLocal<String> threadLocal = new ThreadLocal<>();
public InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
ThreadLocalTest threadLocalTest = new ThreadLocalTest();
threadLocalTest.set();
Thread t1 =new Thread(){
@Override
public void run() {
super.run();
threadLocalTest.get();
}
};
threadLocalTest.get();
t1.start();
}
public void set(){
string = "hello string ";
//set方法中将该值保存在线程的threadLocals中
threadLocal .set("hello threadLocal ");
//set方法中将该值保存在线程的inheritableThreadLocals 中
inheritableThreadLocal.set("hello inheritableThreadLocal ");
}
private void get(){
System.out.println(string);
System.out.println(threadLocal.get());
System.out.println(inheritableThreadLocal.get());
}
}
//hello string
//hello threadLocal
//hello inheritableThreadLocal
//hello string
//null
//hello inheritableThreadLocal
每一个线程都拥有这两个变量,所以它们的作用域是线程相关的。Spring的Bean默认都是单例的,但是服务器对每一个请求都是单独的一个线程,一些属性相对于每一个请求而存在,就不能作为全局变量存在于单例的Bean中,这样容易被其他线程污染。ThreadLocal变量的作用域就可以解决这个问题,InheritableThreadLocal的变量在构成父子关系的多个线程中存在,如上在main线程中的新建的t1线程继承了main线程中的InheritableThreadLocal的值。在新建每一个线程的时候,会检查父线程的inheritableThreadLocals对象是否为空,不为空则将inheritableThreadLocals的值拷贝出来赋给子线程。