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. sublime安装LiveReload(写完代码再也不用手动刷新浏览器了)【转】

    1.首先在chrome下安装这个扩展程序 LiveReload 2.在sublime下按快捷键 ctrl+shift+p  点击截图标的位置 按回车 输入LiveReload 即可下载 然后打开 {改 ...

  2. apache2 配置入门

    ServerRoot "/usr/local/apache2" #服务器根目录 Listen #监听端口 语法格式为Listen [IP地址:]端口 [协议],其中IP地址与协议为 ...

  3. 5G如何让智能手机再次变得丑陋?

    第一批5G移动终端将于明年到货,这意味着智能手机制造商现在正在研究细节.与过去十年智能手机所看到的很多其他组件改进不同,像更好的相机,更快的处理器和更亮的屏幕,5G无线电将需要一些设计上的妥协,而且看 ...

  4. js中数组Array 详解

    unshift:将参数添加到原数组开头,并返回数组的长度    pop:删除原数组最后一项,并返回删除元素的值:如果数组为空则返回undefined    push:将参数添加到原数组末尾,并返回数组 ...

  5. 通过ssh访问虚拟机中的ubuntu系统

    首先把 network 连接方式由 NAT 改为 Bridge Adapter,这样虚拟机中的 ubuntu 就可以有独立的 IP 地址. 安装 openssh: sudo apt-get insta ...

  6. dubbo所用到的技术

    服务注册:zookeeper 协议:dubbo  Hessian  Rmi 网络编程:netty 动态代理:jdk和Javassist 序列化:Hessian  Dubbo  Json  Java S ...

  7. 【Eureka】实现原理

    Eureka Client 拉取Eureka Server中的全量注册表 注册自身实例InstanceInfo至Eureka Server 初始化定时任务 心跳(续约)任务 拉取增量注册表更新本地注册 ...

  8. Struts第一个程序。

    1:创建完程序后.先写web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmln ...

  9. 【Java】使用Lambda排序集合

    下面是Java lambda表达式的简单例子: // 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. ...

  10. python-zx笔记3-函数

    一.调用函数 在交互式命令行通过help(abs)查看abs函数的帮助信息 把函数名赋给一个变量 a = abs 二.定义函数 求解方程:ax2 + bx + c = 0 # -*- coding: ...