一、何为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. 【Linux】linux的所有文件分类解析

    今天看书的时候,无意间看到/dev/文件夹,以前没注意,今天去看了下发现,很多文件的开头文件属性都是一些不怎么见到的 常见的是   -     这个是代表文件,可以vim编辑的 d     这个是代表 ...

  2. 【ORA】ORA-39002,ORA-39070,ORA-29283, ORA-06512,ORA-29283解决办法

    今天使用IMPDP导入的时候报了一个错误 ORA-39002: invalid operation  ORA-39070: Unable to open the log file.  ORA-2928 ...

  3. buuctf—web—高明的黑客

    打开靶机,看到如下界面 于是打开www.tar.gz 下载后发现是一个放有大量php文件的文件夹 看了大佬的wp后明白了是fuzzing 附上大佬的脚本 import os import re imp ...

  4. library cache pin解决方法

    library cache pin大部分都是因为编译存储过程造成的 查找造成问题的数据库对象(一般为存储过程) SELECT * FROM v$session_wait WHERE event = ' ...

  5. TSP旅行商问题

    求解的问题,burma.tsp里面的内容 1 16.47 96.10 2 16.47 94.44 3 20.09 92.54 4 22.39 93.37 5 25.23 97.24 6 22.00 9 ...

  6. 内存空间有限情况下的词频统计 Trie树 前缀树

    数据结构与算法专题--第十二题 Trie树 https://mp.weixin.qq.com/s/nndr2AcECuUatXrxd3MgCg

  7. http://golang.org/s/better-linker

    http://golang.org/s/better-linker The original linker was also simpler than it is now and its implem ...

  8. Paginator Django 分页 When QuerySets are evaluated QuerySets 执行原理 QuerySets are lazy 惰性执行 访问db取数据的时机

    https://docs.djangoproject.com/en/2.2/topics/pagination/ Paginator objects¶ The Paginator class has ...

  9. 【LinuxShell】cp 用法详解

    Linux cp命令主要用于复制文件或目录. -a:此选项通常在复制目录时使用,它保留链接.文件属性,并复制目录下的所有内容.其作用等于dpR参数组合. -d:复制时保留链接.这里所说的链接相当于Wi ...

  10. HDU1823 Luck ans Love 二维线段树

    Luck and Love HDU - 1823 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你                 ―― 张小娴 前段日子,枫冰叶子给Wiskey ...