一、何为ThreadLocal

1、ThreadLocal的含义

ThreadLocal,即线程变量,是一个以ThreadLocal对象为键,任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。

2、ThreadLocal的实用意义

每个线程拥有自己的局部变量毫无疑问比使用全局变量好,因为局部的变量只有县城自己能看见,而不会影响到其他线程。ThreadLocal本身能被多个线程共享使用,并且又能达到线程安全的目的。常用的就是get、set、initialValue等方法。

3、使用ThreadLocal前你必须知道的

JDK建议将ThreadLocal定义为private static类型。

ThreadLocal最常用的地方就是为每个线程绑定一个数据连接、HTTP请求、用户身份信息等,这样一个线程的所有调用到的方法都可以非常方便地访问这些资源。

二、ThreadLocal的使用

1、创建和初始化ThreadLocal

我们只需直接用new的方式创建ThreadLocal变量,并使用一个泛型参数指定ThreadLocal的类型。如果ThreadLocal的初始值不被设定,它的默认初始值将被设定为null,如果要更改初始值,我们通常有两种方法:

  • 使用实现了initialValue的匿名内部类
  • 使用ThreadLocal的类方法withInitial(),参数使用lambda表达式

    这两种方法都是在new一个ThreadLocal对象时使用。
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

 //如果要更改初始值
//方法一 需要一个继承了ThreadLocal父类,重写了initialValue方法的类,用它来创建ThreadLocal类对象
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(){ //这里使用匿名内部类
@Override
protected Integer initialValue() {
return 200; //初始化的值由null变成200
}
}; //方法二 使用withIntial方法
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);

2、获取和设置ThreadLocal的值

使用get和set方法即可

private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);
//获取值
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());//get获取值
//设置值
threadLocal.set(99);//set设置值

三、ThreadLocal的一个简单示例

public class ThreadLocalTest {
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1);
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread(new MyRun()).start();
}
} //内部类
public static class MyRun implements Runnable{
@Override
public void run() {
Integer left = threadLocal.get();
System.out.println(Thread.currentThread().getName()+"得到了-->"+left);
threadLocal.set(left-1);
System.out.println(Thread.currentThread().getName()+"还剩下-->"+threadLocal.get());
}
}
}

四、ThreadLocal的上下文环境分析

注意,在ThreadLocal的使用中,get到的值的来源有以下规律

  • 在构造器中试图get:哪个线程调用了构造器就get到哪个线程的ThreadLocal的值
  • 在run方法中或其调用的方法中试图get:get该线程自己的ThreadLocal的值

    以下是一个示例
public class ThreadLocalTest {
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1); public static void main(String[] args) {
new Thread(new MyRun()).start(); //如果构造器中有读写ThreadLocal,这里设置的是main线程
} //内部类
public static class MyRun implements Runnable{
public MyRun() {
//构造器是哪里调用就属于哪里。这里是main调用的,所以设置和打印的都是main的ThreadLocal的值
threadLocal.set(100);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
} @Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
//new Thread(new MyRun()).start(); //如果在这里又new一个MyRun对象,就要调用构造器,其中set和get的,就是这里这个线程的ThreadLocal的值
}
}
}

五、ThreadLocal和Synchronized的对比

ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不同的点是

  • Synchronized是通过线程等待,牺牲时间来解决访问冲突
  • ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。

正因为ThreadLocal的线程隔离特性,使他的应用场景相对来说更为特殊一些。在android中Looper、ActivityThread以及AMS中都用到了ThreadLocal。当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。

ThreadLocal使用全解的更多相关文章

  1. Mybatis系列全解(六):Mybatis最硬核的API你知道几个?

    封面:洛小汐 作者:潘潘 2020 年的大疫情,把世界撕成几片. 时至今日,依旧人心惶惶. 很庆幸,身处这安稳国, 兼得一份安稳工. · 东家常讲的一个词:深秋心态 . 大势时,不跟风.起哄, 萧条时 ...

  2. 易全解token获取

    //易全解app             string strClientID = "2016061711434943493606";             string str ...

  3. IOS-UITextField-全解

    IOS-UITextField-全解   //初始化textfield并设置位置及大小   UITextField *text = [[UITextField alloc]initWithFrame: ...

  4. 什么是JavaScript闭包终极全解之一——基础概念

    本文转自:http://www.cnblogs.com/richaaaard/p/4755021.html 什么是JavaScript闭包终极全解之一——基础概念 “闭包是JavaScript的一大谜 ...

  5. Sql Server函数全解<五>之系统函数

    原文:Sql Server函数全解<五>之系统函数  系统信息包括当前使用的数据库名称,主机名,系统错误消息以及用户名称等内容.使用SQL SERVER中的系统函数可以在需要的时候获取这些 ...

  6. Sql Server函数全解<四>日期和时间函数

    原文:Sql Server函数全解<四>日期和时间函数   日期和时间函数主要用来处理日期和时间值,本篇主要介绍各种日期和时间函数的功能和用法,一般的日期函数除了使用date类型的参数外, ...

  7. 九度oj题目&amp;吉大考研11年机试题全解

    九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码).    http://ac.jobdu.com/problem.php?pid=11 ...

  8. js系列教程2-对象、构造函数、对象属性全解

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...

  9. js系列教程1-数组操作全解

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...

随机推荐

  1. 【ORACLE】11g rac+dg

    首先感谢群友分享的文档,在这里先感谢哆啦B梦,非常感谢 该文档主要指导如何利用现有的RAC环境搭建一套RAC与单实例的DG的环境  ============================主机配置信息 ...

  2. SAP client锁定

    今天发现一个函数可以锁定SAP CLIENT . SCCR_LOCK_CLIENT 参数是client号码. 还可以通过事物SU10批量锁定用户登陆client

  3. SAP系统跨平台字符编码转换

    SAP系统在进行了夸平台的迁移,可能会遇到操作系统层文件编码不同,导致SAP系统无法识别或者乱码的问题.例如SAP系统从AIX平台迁移到linux平台,SAP应用服务器的编码会发生变化,从4102变化 ...

  4. 04--Docker数据卷和数据卷容器

    .为什么要使用数据卷: Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了.为了能保存数据在docke ...

  5. Flask的“中间件”

    特殊装饰器 from flask import Flask,render_template,request app = Flask(__name__) @app.before_request def ...

  6. 07. struts2中对Action的管理方式

    web.xml配置文件的常用代码 <filter> <filter-name>struts2</filter-name> <filter-class>o ...

  7. 3.kafka安装配置

    kafka安装配置 ### 1.集群规划 hadoop102 hadoop103 hadoop104 zk zk zk kafka kafka kafka jar包下载 http://kafka.ap ...

  8. 记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST_网络_c359719435的专栏-CSDN博客 https://blog.csdn.net/c359719435/article/details/80300433

    记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST_网络_c359719435的专栏-CSDN博客 https://blog.csdn.net/c3 ...

  9. (转载)微软数据挖掘算法:Microsoft Naive Bayes 算法(3)

    介绍: Microsoft Naive Bayes 算法是一种基于贝叶斯定理的分类算法,可用于探索性和预测性建模. Naïve Bayes 名称中的 Naïve 一词派生自这样一个事实:该算法使用贝叶 ...

  10. Qedis实现

    对比redis的Qedis 实现在github 和 实验楼都有资料