另一个角度理解java的ThreadLocal
程序员文章站
2022-07-12 13:10:57
...
关于Java的ThreadLocal网上有大量的文章在谈这个问题,为什么这个东西大家说来说去乐此不疲呢,大约是因为它本身的神秘性,经常出现在一些框架中,但是自己又很少用。亦或是因为大家本身对它的理解各有偏颇,所以成了大家热议的话题。
我对ThreadLocal的理解也不深,这篇文章也不会去做什么深层次的研究,对源码分析的文章也有很多写的非常好的,我只是想从另外一个角度去认识ThreadLocal。
ThreadLocal被翻译成“线程本地变量”,从名字上讲首先它是“变量”,那么,我们就来看看Java中的各种变量。
一、局部变量
定义:方法中,代码块中,方法参数中定义的变量。
作用域:方法内部,代码块内部。其他方法,其他代码块不能访问。
生命周期:方法或者代码块调用开始到方法或者代码块调用结束。
共享性:方法内部,代码块内部共享,对于多个线程来讲,变量初始化到自己的工作内存中,主内存不存在该变量,所以线程之间不共享。
例子:
同一个类中的method1和method2中都可以定义一个名为a的变量,同样method1中的for代码块,if代码块和{}代码块中都可以定义名为i的变量。它们的作用域都在方法内部或者代码块内部。
二、成员变量
定义:成员变量又称为成员属性,它是描述对象状态的数据,是类中很重要的组成成分。
作用域:整个类实例内部。
生命周期:伴随整个类实例始终,变量在创建类实例时被创建。
共享性(同一个类实例):在整个类实例共享,对于多线程来讲,变量被初始化到主内存中,每个线程拷贝变量到工作内存中进行操作,线程之间共享一个主内存变量,存在线程安全问题。
例子:
对于同一个Clazz类的实例来讲,变量a的作用域存在于整个Clazz实例,如果多线程之间共享一个Clazz实例,变量a是存在线程安全问题的。
三、全局变量
定义:全局变量在Java中也可以叫静态变量,通过static关键字修饰。
作用域:整个类。
生命周期:伴随整个类始终,变量在第一次使用该类时被创建。
共享性:在整个类共享,对于多线程来讲,变量被初始化到主内存中,每个线程拷贝变量到工作内存中进行操作,线程之间共享一个主内存变量,存在线程安全问题。
说了这么多,那么跟ThreadLocal有什么关系呢?
思考为什么要定义这么多的变量类型呢?
局部变量解决了方法内部,代码块内部行之间的变量传递问题。如果没有局部变量,不知道行之间怎么传递变量。
成员变量解决了类实例各方法之间的变量传递。如果没有成员变量,方法之间变量传递只能靠参数。
全局变量解决了类之间的变量传递。如果没有全局变量,类之间变量只能靠构造实例的时候相互传递。
那么ThreadLocal也是变量,该变量解决了什么问题呢?
ThreadLocal解决了变量在同一个线程内部之间的传递。
ThreadLocal首先不是解决线程安全问题,最显而易见的原因是ThreadLocal内部保存的变量在多线程之间不共享。数据都不共享,谈何线程安全?当然了,如果ThreadLocal内部保存的变量本身就是一个多线程共享的数据,那么还是会有线程安全的问题的。如果没有ThreadLocal,我们需要在同一个线程之内共享的数据大约只能通过方法传递了。这样可能会让代码显得杂乱。
四、ThreadLocal变量
定义:线程本地变量。
作用域:线程内部。
生命周期:伴随线程执行始终,线程结束,变量生命结束。
共享性:多个线程之间不共享。
我对ThreadLocal的理解也不深,这篇文章也不会去做什么深层次的研究,对源码分析的文章也有很多写的非常好的,我只是想从另外一个角度去认识ThreadLocal。
ThreadLocal被翻译成“线程本地变量”,从名字上讲首先它是“变量”,那么,我们就来看看Java中的各种变量。
一、局部变量
定义:方法中,代码块中,方法参数中定义的变量。
作用域:方法内部,代码块内部。其他方法,其他代码块不能访问。
生命周期:方法或者代码块调用开始到方法或者代码块调用结束。
共享性:方法内部,代码块内部共享,对于多个线程来讲,变量初始化到自己的工作内存中,主内存不存在该变量,所以线程之间不共享。
例子:
public void method1() { //方法执行到此处时变量a才被创建。 int a=1; for (int i=0; i<10; i++) { System.out.println(i); } if (true) { int i= 2; } { int i=3; } } public void method2() { int a=2; }
同一个类中的method1和method2中都可以定义一个名为a的变量,同样method1中的for代码块,if代码块和{}代码块中都可以定义名为i的变量。它们的作用域都在方法内部或者代码块内部。
二、成员变量
定义:成员变量又称为成员属性,它是描述对象状态的数据,是类中很重要的组成成分。
作用域:整个类实例内部。
生命周期:伴随整个类实例始终,变量在创建类实例时被创建。
共享性(同一个类实例):在整个类实例共享,对于多线程来讲,变量被初始化到主内存中,每个线程拷贝变量到工作内存中进行操作,线程之间共享一个主内存变量,存在线程安全问题。
例子:
public class Clazz { private int a; public void method() { a ++; } }
对于同一个Clazz类的实例来讲,变量a的作用域存在于整个Clazz实例,如果多线程之间共享一个Clazz实例,变量a是存在线程安全问题的。
三、全局变量
定义:全局变量在Java中也可以叫静态变量,通过static关键字修饰。
作用域:整个类。
生命周期:伴随整个类始终,变量在第一次使用该类时被创建。
共享性:在整个类共享,对于多线程来讲,变量被初始化到主内存中,每个线程拷贝变量到工作内存中进行操作,线程之间共享一个主内存变量,存在线程安全问题。
public class Clazz { public static int a = 0; }
说了这么多,那么跟ThreadLocal有什么关系呢?
思考为什么要定义这么多的变量类型呢?
局部变量解决了方法内部,代码块内部行之间的变量传递问题。如果没有局部变量,不知道行之间怎么传递变量。
成员变量解决了类实例各方法之间的变量传递。如果没有成员变量,方法之间变量传递只能靠参数。
全局变量解决了类之间的变量传递。如果没有全局变量,类之间变量只能靠构造实例的时候相互传递。
那么ThreadLocal也是变量,该变量解决了什么问题呢?
ThreadLocal解决了变量在同一个线程内部之间的传递。
ThreadLocal首先不是解决线程安全问题,最显而易见的原因是ThreadLocal内部保存的变量在多线程之间不共享。数据都不共享,谈何线程安全?当然了,如果ThreadLocal内部保存的变量本身就是一个多线程共享的数据,那么还是会有线程安全的问题的。如果没有ThreadLocal,我们需要在同一个线程之内共享的数据大约只能通过方法传递了。这样可能会让代码显得杂乱。
四、ThreadLocal变量
定义:线程本地变量。
作用域:线程内部。
生命周期:伴随线程执行始终,线程结束,变量生命结束。
共享性:多个线程之间不共享。