ThreadLocal是个threadlocalvariable(线程局部变量),其实就是为每一个使用该变量的线程都提供一个变量值的副本,从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
 
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
 
实例:
public class Student {
private int age = 0; //年龄 public int getAge() {
return this.age;
} public void setAge(int age) {
this.age = age;
}
} public class ThreadLocalDemo implements Runnable {
//创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
private final static ThreadLocal studentLocal = new ThreadLocal(); public static void main(String[] agrs) {
ThreadLocalDemo td = new ThreadLocalDemo();
Thread t1 = new Thread(td, "a");
Thread t2 = new Thread(td, "b");
t1.start();
t2.start();
} public void run() {
accessStudent();
} /**
* 示例业务方法,用来测试
*/
public void accessStudent() {
//获取当前线程的名字
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
//产生一个随机数并打印
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
//获取一个Student对象,并将随机数年龄插入到对象属性中
Student student = getStudent();
student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());
try {
Thread.sleep(500);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());
} protected Student getStudent() {
//获取本地线程变量并强制转换为Student类型
Student student = (Student) studentLocal.get();
//线程首次执行此方法的时候,studentLocal.get()肯定为null
if (student == null) {
//创建一个Student对象,并保存到本地线程变量studentLocal中
student = new Student();
studentLocal.set(student);
}
return student;
}
}

运行结果:

a is running!
thread a set age to:76
b is running!
thread b set age to:27
thread a first read age is:76
thread b first read age is:27
thread a second read age is:76
thread b second read age is:27

ThreadLocal和synchronized的比较:

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区 别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本, 使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通 信时能够获得数据共享。
 
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
 
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
 
ThreadLocal的一般使用步骤:
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。

ThreadLocal的使用和理解的更多相关文章

  1. Threadlocal线程本地变量理解

    转载:https://www.cnblogs.com/chengxiao/p/6152824.html 总结: 作用:ThreadLocal 线程本地变量,可用于分布式项目的日志追踪 用法:在切面中生 ...

  2. servlet 和 threadlocal 与 web容器(理解threadlocal)

    同步机制采用了“以时间换空间”的方式,提供一份变量,让不同的线程排队访问.而ThreadLocal采用了“以空间换时间”的方式,为每一个线程都提供了一份变量的副本,从而实现同时访问而互不影响. htt ...

  3. 【Java】深入理解ThreadLocal

    一.前言 要理解ThreadLocal,首先必须理解线程安全.线程可以看做是一个具有一定独立功能的处理过程,它是比进程更细度的单位.当程序以单线程运行的时候,我们不需要考虑线程安全.然而当一个进程中包 ...

  4. [转]POJO中使用ThreadLocal实现Java嵌套事务

    大多嵌套事务都是通过EJB实现的,现在我们尝试实现对POJO的嵌套事务.这里我们使用了ThreadLocal的功能. 理解嵌套事务 事务是可以嵌套的.所以内层事务或外层事务可以在不影响其他事务的条件下 ...

  5. 结合ThreadLocal来看spring事务源码,感受下清泉般的洗涤!

    在我的博客spring事务源码解析中,提到了一个很关键的点:将connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection.但是没有细致的讲到如何绑定,以及为什么这么 ...

  6. 【Java并发系列03】ThreadLocal详解

    img { border: solid 1px } 一.前言 ThreadLocal这个对象就是为多线程而生的,没有了多线程ThreadLocal就没有存在的必要了.可以将任何你想在每个线程独享的对象 ...

  7. ThreadLocal源码解读

    1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很有问题,包括百度搜索出来的第一篇高访问量博文,说ThreadLocal内部有个map,键为线程对象 ...

  8. ThreadLocal 简介 案例 源码分析 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  9. 详解一个ThreadLocal 的谜题

    多线程如果不理解透彻, 那么 ThreadLocal 始终是有些会有所迷糊的. ThreadLocal 本身的命名有有问题, 这些美国精英整出来的技术,再加上一个奇怪的命名.对我们中国人来说,就是一场 ...

随机推荐

  1. css盒子模型的宽度不包括margin

    看到教程上和一些博客上盒子模型的宽度 = content + padding + margin + border,应该是不包括margin的 <!DOCTYPE html> <htm ...

  2. vue之路由传参三种基本方式

    现有如下场景,点击父组件的li元素跳转到子组件中,并携带参数,便于子组件获取数据. 父组件中: <li v-for="article in articles" @click= ...

  3. 前端每日实战:56# 视频演示如何用纯 CSS 描述程序员的生活

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/YvYVvY 可交互视频 此视频是可 ...

  4. 1.xml简单介绍

    1.xml(eXtensible Markup Language)的简介 (1)xml: 可扩展标记型语言 - 标记型语言:例如html也是标记型语言,也是使用标签来操作的 - 可扩展:html里面的 ...

  5. pandas.DataFrame.sample

    DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)[sourc ...

  6. Linux进程前后台管理(&,fg, bg)

    将进程置于后台 xlogo & 会把进程置于后台管理,使用ps命令查看进程 PID. 使用命令jobs [1]+ Running xlogo & 可以看到正在运行的 xlogo 进程. ...

  7. C#基础提升系列——C# LINQ

    C# LINQ LINQ(Language Integrated Query,语言集成查询).在C# 语言中集成了查询语法,可以用相同的语法访问不同的数据源. 命名空间System.Linq下的类En ...

  8. python每日练习

    """ 习题 1:一个列表,排重,不能用 set,也不能用字典 """ #方法一1:循环.遍历 l = [1,1,1,2,2,3,4,4,6 ...

  9. 阿里云基于OSS的云上统一数据保护方案2.0技术解析

    近年来,随着越来越多的企业从传统经济向数字经济转型,云已经渐渐成为数据经济IT新常态.核心业务系统上云,云上的业务创新,这些都产生了大量的业务数据,这些数据也成为了企业最重要的资产.资源. 阿里云基于 ...

  10. sql语句中取整数和小数部分

    sql 取整数去小数点 ,) ' Sql截取浮点小数位数,不四舍五入 ,) 结果:551.24 ,) 结果:551.23 第一个2表示截取2位 第二个0,1分别表示0是四舍五入,0以外是截取 如何分别 ...