ThreadLocal使用的情景和原理
线程本地存储,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。这是防止多线程在资源上产生冲突的第二种方式,即每个线程都有一个完整的副本,
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
理解threadLocal和thread从下面两个点出发,很清晰:
先看获取某个threadLocal值过程:
获取当前线程及其threadLocalMap -- 某threadLocal同时用到多个多个thread
threadlocalMap中以threadLocal为key获取value -- 某线程中有多个threadLocal
1 threadLocal被多个thread调用,怎么区分多个thread呢?
每个thread中有一个thread.threadLocalMap,threadLocal被某个thread调用时会获取该thread的threadLocalMap
2 某个thread可以使用多个threadLocal,所以为了区分这些threadLocal,threadLocalMap结构为:
key-threadLocal
value-object
当多个线程需要使用同一个对象,并且需要该对象具有相同的初始化值 的情景下使用ThreadLocal
实例:
package concurrencypractice.jingtong.review;
public class MythreadExtendsThread extends Thread{
private sequenceB sequence;
public MythreadExtendsThread(sequenceB sequence){
this.sequence=sequence;
}
public void run(){
// TODO Auto-generated method stub
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" i="+i+"sequence.getNumber()"+sequence.getNumber());
try {
Thread.sleep(i*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package concurrencypractice.jingtong.review;
public class sequenceB {
private static ThreadLocal<Integer> numberContainer=new ThreadLocal<Integer>()/*{
//threadLocal赋初值的方法一
protected Integer initialValue(){
return 0;
}
}*/;
public int getNumber(){
//threadLocal赋初值方法二
if(numberContainer.get()==null){
numberContainer.set(0);
}else{
numberContainer.set(numberContainer.get()+1);
}
return (int) numberContainer.get();
}
public static void main(String[] args) {
sequenceB sequnce=new sequenceB();
MythreadExtendsThread thread=new MythreadExtendsThread(sequnce);
MythreadExtendsThread thread1=new MythreadExtendsThread(sequnce);
MythreadExtendsThread thread2=new MythreadExtendsThread(sequnce);
thread.start();
thread1.start();
thread2.start();
}
}
打印结果
Thread-1 i=0sequence.getNumber()0
Thread-2 i=0sequence.getNumber()0
Thread-0 i=0sequence.getNumber()0
Thread-2 i=1sequence.getNumber()1
Thread-1 i=1sequence.getNumber()1
Thread-0 i=1sequence.getNumber()1
Thread-1 i=2sequence.getNumber()2
Thread-2 i=2sequence.getNumber()2
Thread-0 i=2sequence.getNumber()2
ThreadLocal的底层原理分析
本质上是每个线程内部有一个ThreadLocalMap,所以获取threadLocalmap需要先获取当前线程;该threadLocalMap中key为threadLocal自身,value为真实的值。
提供的方法: 先了解一下ThreadLocal类提供的几个方法:
1 2 3 4 |
public T get() { } public void set(T value) { } public void remove() { } protected T initialValue() { } |
get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法,下面会详细说明。
先看下get方法的实现:
第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对,注意这里获取键值对传进去的是 this(就是ThreadLocal对象),而不是当前线程t。
如果获取成功,则返回value值。
如果map为空,则调用setInitialValue方法返回value。
我们上面的每一句来仔细分析:
首先看一下getMap方法中做了什么:
可能大家没有想到的是,在getMap中,是调用当期线程t,返回当前线程t中的一个成员变量threadLocals。
那么我们继续取Thread类中取看一下成员变量threadLocals是什么:
实际上就是一个ThreadLocalMap,这个类型是ThreadLocal类的一个内部类,我们继续取看ThreadLocalMap的实现:
可以看到ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。
然后再继续看setInitialValue方法的具体实现:
很容易了解,就是如果map不为空,就设置键值对,为空,再创建Map,看一下createMap的实现:
至此,可能大部分朋友已经明白了ThreadLocal是如何为每个线程创建变量的副本的:
首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。
初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。
1)实际的通过ThreadLocal创建的副本是存储在每个线程自己的threadLocals中的;
2)为何threadLocals的类型ThreadLocalMap的键值为ThreadLocal对象,因为每个线程中可有多个threadLocal变量,就像上面代码中的numberContainer
3)在进行get之前,必须先set,如果没有set则会调用setInitialValue初始化threadLocals,否则会返回null;
理解threadLocal和thread从下面两个点出发,很清晰:
1 threadLocal被多个thread调用,怎么区分多个thread呢?
每个thread中有一个thread.threadLocalMap,threadLocal被某个thread调用时会获取该thread的threadLocalMap
2 某个thread可以使用多个threadLocal,所以为了区分这些threadLocal,threadLocalMap结构为:
key-threadLocal
value-object
借鉴:
https://www.cnblogs.com/dolphin0520/p/3920407.html
ThreadLocal使用的情景和原理相关推荐
- java并发(3)ThreadLocal的使用及实现原理(实现原理)
在上一篇文章java并发(2)ThreadLocal的使用及实现原理(使用)中介绍了ThreadLocal的简单使用,这篇文章通过jdk8ThreadLocal的源码分析一下ThreadLocal的实 ...
- ThreadLocal的正确使用与原理
ThreadLocal是什么 ThreadLocal是线程Thread中属性threadLocals即ThreadLocal.ThreadLocalMap的管理者,ThreadLocal用于给每个线程 ...
- ThreadLocal用法详解和原理
转载自 https://blog.csdn.net/danengbinggan33/article/details/73105838 一.用法 ThreadLocal用于保存某个线程共享变量:对于同一 ...
- 这是利基运动对当今平面设计师的巨大影响的核心
By Emily Gosling 艾米丽·高斯林(Emily Gosling) For the uninitiated, hardcore was a subgenre of punk that ha ...
- ThreadLocal的使用及原理分析
文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...
- c++ socket线程池原理_一篇文章看懂 ThreadLocal 原理,内存泄露,缺点以及线程池复用的值传递问题...
编辑:业余草来源:https://www.xttblog.com/?p=4946 一篇文章看懂 ThreadLocal 原理,内存泄露,缺点以及线程池复用的值传递问题. ThreadLocal 相信不 ...
- ThreadLocal内存泄漏原理解析
1.什么是内存泄漏问题? 内存泄漏 表示就是我们申请了内存,但是该内存一直无法释放: 内存泄漏会导致内存溢出问题: 申请内存时,发现申请内存不足,就会报错 : 2.在介绍ThreadLocal内存泄漏 ...
- Java 并发编程:ThreadLocal 的使用及其源码实现
1.ThreadLocal的使用 防止任务在共享资源上产生冲突的一种方式是根除对变量的共享,使用线程的本地存储为使用相同变量的不同线程创建不同的存储. 下面是一个 ThreadLocal 的实例.这里 ...
- Guava 源码分析(Cache 原理)
作者:crossoverJie's Blog 来源:https://crossoverjie.top/2018/06/13/guava/guava-cache/ 前言 Google 出的 Guava ...
最新文章
- http://blog.51cto.com/wbb827/1175634
- 从代码层读懂Java HashMap的实现原理
- 简单直接的方法解析JSON数据
- JVM_04 字符串常量池(详解intern( ))
- python3.5安装scrapy_Python3.5 win7安装scrapy
- Java LinkedList公共int indexOf(Object o)方法(带示例)
- 什么不用 iframe 做微前端
- A10负载均衡设备基础配置
- PyTorch学习笔记——语言模型
- html页面添加视频背景设置为自动播放,打开网址就会自动播放,简单有效亲测
- php5.6 mongo 扩展,docker php5.6镜像创建,包括常用扩展安装
- openwrt的源码下载及其编译 (一)
- 基于蒙特卡诺的风场景模型出力(Matlab代码实现)
- iOS - 毛玻璃效果
- 口令订单红包V1.1.3公众号源码,增加关注多久后才能使用口令与领取红包功能
- jmeter优化记录文档
- ajax去掉session,PHP中解决ajax请求session过时退出登陆问题
- 计算机网络 第3章 作业1
- 中国蚁剑安装使用教程
- Vue CLI 官方文档(一)@vue/cli、@vue/cli-service、插件和 Preset
热门文章
- 【教程】建立 局域网下数据互通 的 共享磁盘/文件夹
- [音乐]歌手萨顶顶及其专辑万物生
- java工具类之导出Excel
- 关于社会性软件、IM和p2p等的随想
- 水平螺旋输送机的设计(说明书+CAD图纸+任务书+评阅表+鉴定意见+外文)
- 艺点教你制作好看的动画POSE
- C++面向对象编程介绍
- Xshell免费使用办法,免注册码,免破解,Xsell过期了怎么办?不实就删帖
- 什么样的域名有助于网络营销的seo优化(自然排名) 上海添力
- 复旦大学2018--2019学年第一学期(18级)高等代数I期末考试第八大题解答