ThreadLocal使用全解
一、何为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使用全解的更多相关文章
- Mybatis系列全解(六):Mybatis最硬核的API你知道几个?
封面:洛小汐 作者:潘潘 2020 年的大疫情,把世界撕成几片. 时至今日,依旧人心惶惶. 很庆幸,身处这安稳国, 兼得一份安稳工. · 东家常讲的一个词:深秋心态 . 大势时,不跟风.起哄, 萧条时 ...
- 易全解token获取
//易全解app string strClientID = "2016061711434943493606"; string str ...
- IOS-UITextField-全解
IOS-UITextField-全解 //初始化textfield并设置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame: ...
- 什么是JavaScript闭包终极全解之一——基础概念
本文转自:http://www.cnblogs.com/richaaaard/p/4755021.html 什么是JavaScript闭包终极全解之一——基础概念 “闭包是JavaScript的一大谜 ...
- Sql Server函数全解<五>之系统函数
原文:Sql Server函数全解<五>之系统函数 系统信息包括当前使用的数据库名称,主机名,系统错误消息以及用户名称等内容.使用SQL SERVER中的系统函数可以在需要的时候获取这些 ...
- Sql Server函数全解<四>日期和时间函数
原文:Sql Server函数全解<四>日期和时间函数 日期和时间函数主要用来处理日期和时间值,本篇主要介绍各种日期和时间函数的功能和用法,一般的日期函数除了使用date类型的参数外, ...
- 九度oj题目&吉大考研11年机试题全解
九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码). http://ac.jobdu.com/problem.php?pid=11 ...
- js系列教程2-对象、构造函数、对象属性全解
全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...
- js系列教程1-数组操作全解
全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...
随机推荐
- C语言字符串结束符“\0”
介绍 '\0'就是8位的00000000,因为字符类型中并没有对应的这个字符,所以这么写.'\0'就是 字符串结束标志. '\0'是转译字符,意思是告诉编译器,这不是字符0,而是空字符.空字符\0对应 ...
- PYTHON爬虫实战_垃圾佬闲鱼爬虫转转爬虫数据整合自用二手急速响应捡垃圾平台_3(附源码持续更新)
说明 文章首发于HURUWO的博客小站,本平台做同步备份发布. 如有浏览或访问异常图片加载失败或者相关疑问可前往原博客下评论浏览. 原文链接 PYTHON爬虫实战_垃圾佬闲鱼爬虫转转爬虫数据整合自用二 ...
- LSTM+CRF进行序列标注
为什么使用LSTM+CRF进行序列标注 直接使用LSTM进行序列标注时只考虑了输入序列的信息,即单词信息,没有考虑输出信息,即标签信息,这样无法对标签信息进行建模,所以在LSTM的基础上引入一个标签转 ...
- 安装jdk-windows系统
1. 明确需要安装的jdk版本,注意jdk存在小版本号,例如jdk1.7_51,如果不清楚小版本号的话建议安装最新版本的jdk: 2. 打开cmd命令窗口,输入java -version查看本机是否安 ...
- 牛逼!MySQL 8.0 中的索引可以隐藏了…
MySQL 8.0 虽然发布很久了,但可能大家都停留在 5.7.x,甚至更老,其实 MySQL 8.0 新增了许多重磅新特性,比如栈长今天要介绍的 "隐藏索引" 或者 " ...
- MySQL全面瓦解21(番外):一次深夜优化亿级数据分页的奇妙经历
背景 1月22号晚上10点半,下班后愉快的坐在在回家的地铁上,心里想着周末的生活怎么安排. 突然电话响了起来,一看是我们的一个开发同学,顿时紧张了起来,本周的版本已经发布过了,这时候打电话一般来说是线 ...
- mybatis源码分析之走进缓存
之前写了一篇关于mybatis缓存的读后感,想了想还是把缓存模块简单分析一下,附赠下载地址:https://github.com/MyBatis/MyBatis-3,github直接搜排名很靠前的. ...
- JavaScript中的Object类型!
3.4.8 Object 类型 ECMAScript 中的对象其实就是一组数据和功能的集合.对象通过 new 操作符后跟对象类型的名称来创建.开发者可以通过创建 Object 类型的实例来创建自己的对 ...
- win server 2019服务器的iis配置以及网站的简单发布
1.首先远程连接到服务器 2.打开服务器管理器 3添加角色和功能 4.安装类型:选择基于角色或基于功能的安装 →服务器角色:从服务器池中选择服务器 5.服务器角色选择Web服务器(iis) 6.功能 ...
- windows桌面快速添加控制面板网络等图标
默认安装后的windows系统只有回收站. rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0