线程本地存储,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使用的情景和原理相关推荐

  1. java并发(3)ThreadLocal的使用及实现原理(实现原理)

    在上一篇文章java并发(2)ThreadLocal的使用及实现原理(使用)中介绍了ThreadLocal的简单使用,这篇文章通过jdk8ThreadLocal的源码分析一下ThreadLocal的实 ...

  2. ThreadLocal的正确使用与原理

    ThreadLocal是什么 ThreadLocal是线程Thread中属性threadLocals即ThreadLocal.ThreadLocalMap的管理者,ThreadLocal用于给每个线程 ...

  3. ThreadLocal用法详解和原理

    转载自 https://blog.csdn.net/danengbinggan33/article/details/73105838 一.用法 ThreadLocal用于保存某个线程共享变量:对于同一 ...

  4. 这是利基运动对当今平面设计师的巨大影响的核心

    By Emily Gosling 艾米丽·高斯林(Emily Gosling) For the uninitiated, hardcore was a subgenre of punk that ha ...

  5. ThreadLocal的使用及原理分析

    文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...

  6. c++ socket线程池原理_一篇文章看懂 ThreadLocal 原理,内存泄露,缺点以及线程池复用的值传递问题...

    编辑:业余草来源:https://www.xttblog.com/?p=4946 一篇文章看懂 ThreadLocal 原理,内存泄露,缺点以及线程池复用的值传递问题. ThreadLocal 相信不 ...

  7. ThreadLocal内存泄漏原理解析

    1.什么是内存泄漏问题? 内存泄漏 表示就是我们申请了内存,但是该内存一直无法释放: 内存泄漏会导致内存溢出问题: 申请内存时,发现申请内存不足,就会报错 : 2.在介绍ThreadLocal内存泄漏 ...

  8. Java 并发编程:ThreadLocal 的使用及其源码实现

    1.ThreadLocal的使用 防止任务在共享资源上产生冲突的一种方式是根除对变量的共享,使用线程的本地存储为使用相同变量的不同线程创建不同的存储. 下面是一个 ThreadLocal 的实例.这里 ...

  9. Guava 源码分析(Cache 原理)

    作者:crossoverJie's Blog 来源:https://crossoverjie.top/2018/06/13/guava/guava-cache/ 前言 Google 出的 Guava  ...

最新文章

  1. http://blog.51cto.com/wbb827/1175634
  2. 从代码层读懂Java HashMap的实现原理
  3. 简单直接的方法解析JSON数据
  4. JVM_04 字符串常量池(详解intern( ))
  5. python3.5安装scrapy_Python3.5 win7安装scrapy
  6. Java LinkedList公共int indexOf(Object o)方法(带示例)
  7. 什么不用 iframe 做微前端
  8. A10负载均衡设备基础配置
  9. PyTorch学习笔记——语言模型
  10. html页面添加视频背景设置为自动播放,打开网址就会自动播放,简单有效亲测
  11. php5.6 mongo 扩展,docker php5.6镜像创建,包括常用扩展安装
  12. openwrt的源码下载及其编译 (一)
  13. 基于蒙特卡诺的风场景模型出力(Matlab代码实现)
  14. iOS - 毛玻璃效果
  15. 口令订单红包V1.1.3公众号源码,增加关注多久后才能使用口令与领取红包功能
  16. jmeter优化记录文档
  17. ajax去掉session,PHP中解决ajax请求session过时退出登陆问题
  18. 计算机网络 第3章 作业1
  19. 中国蚁剑安装使用教程
  20. Vue CLI 官方文档(一)@vue/cli、@vue/cli-service、插件和 Preset

热门文章

  1. 【教程】建立 局域网下数据互通 的 共享磁盘/文件夹
  2. [音乐]歌手萨顶顶及其专辑万物生
  3. java工具类之导出Excel
  4. 关于社会性软件、IM和p2p等的随想
  5. 水平螺旋输送机的设计(说明书+CAD图纸+任务书+评阅表+鉴定意见+外文)
  6. 艺点教你制作好看的动画POSE
  7. C++面向对象编程介绍
  8. Xshell免费使用办法,免注册码,免破解,Xsell过期了怎么办?不实就删帖
  9. 什么样的域名有助于网络营销的seo优化(自然排名) 上海添力
  10. 复旦大学2018--2019学年第一学期(18级)高等代数I期末考试第八大题解答