ThreadLocal 多线程同步关键字
来源:互联网 发布:华讯网络奖金能拿多少 编辑:程序博客网 时间:2024/05/21 09:09
包括:
一. 什么是 ThreadLocal
二. ThreadLocal 类中的方法简介
三. 如何使用ThreadLocal
3.1 3个线程共享一个对象,各自产生序列号
3.2 例子:共享变量a, 使用ThreadLocal 和没有使用的区别
四. ThreadLocal 和同步机制的比较
五.参考
一.什么是ThreadLocal
ThreadLocal并非一个线程,而是一个线程局部变量。它的作用就是为使用该变量的线程都提供一个变量值的副本,每个线程都可
以独立的改变自己的副本,而不会和其他线程的副本造成冲突。
从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而
为多线程环境常出现的并发访问问题提供了一种隔离机制。
ThreadLocal是解决线程安全问题一个很好的思路,ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素
的键为线程对象,而值对应线程的变量副本,由于Key值不可重复,每一个“线程对象”对应线程的“变量副本”,而到达了线程安全。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。
前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
Ps:附带 源码文档
二.ThreadLocal类中的方法简介
由上注释,可以看到,重点需要了解 get() 和 set() 方法:
2.1 get() 方法:
从上代码分析:
1. 得到该线程: Thread t = Thread.currentThread();
2. 根据该线程 拿到一个 ThreadLocalMap。 ThreadLocalMap map = getMap(t);
3. 通过传统的 map 的 get() 方法拿到变量的在该线程中的副本( 该map 的 key 是一个 ThreadLocal 对象,value 是变量的在该线程中的副本)。
此时分析下 ThreadLocalMap:
可以看到,ThreadLocalMap 相当于一个订制的 HashMap,key 为 ThreadLocal 对象,value 为该值,而且是一个静态类,这就意味着 各个变量都放在内存中。了解了这些,其实就可以自己实现自己的 ThreadLocal。
Ps:此时可能会觉得 Key 是 Thread,实际上不是的,虽然第一步和 第二步看起来是 通过 Thread,但是其实 Thread 类中会维护了一个 ThreadLocalMap 的引用。
参考 get 方法,知道了 其实现原理是通过 订制的 hashMap,那么set 方法就好理解了。
2.3 remove() 方法:
至此,了解了 get(),set(),remove() 三个方法。
三. 如何使用ThreadLocal
3.1 3个线程共享一个对象,各自产生序列号那么,对于这个例子来说,首先是3个线程共享了SequenceNumber对象,那么如何才能保证用同一个东西,但是互不影响,这时候就用到了ThreadLocal来实现这个功能。ThreadLocal类中的Map,存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。所以,各个线程都是在各自的副本上做操作,互不影响。
概况说下上述代码流程:
- 首先在SequenceNumber类中创建ThreadLocal对象seqNum,用来保存线程间需要隔离处理的对象。
- 创建一个获取要隔离访问的数据的方法getXxx(),比如上述的public int getNextNum()方法,主要是里面的seqNum.get()方法。
- 在run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
可能会有个疑问:创建3个线程,这3个线程是什么时候存到ThreadLocal的Map里面的,而且是怎么存放的,get方法取出的时候怎么知道取哪一个。
首先解决是什么时候这3个线程存放到Map里面的,其实是在上述代码调用public int getNextNum()中的seqNum.get()方法,也就是 在 setInitialValue() 的时候,当初始化发现没有该线程在 ThreadLocal 中的时候,则会 加入:
输出为:
此程序两个线程都使用了共享变量,但是没有使用相应的处理多线程问题的方法,所以会出现错误,这不难理解。以下是 经过 ThreadLocal处理的解决:输出为:ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。
在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线 程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编 写多线程代码时,可以把不安全的变量封装进ThreadLocal。
当 然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了 同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的 有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线 程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所 以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间 的共享冲突,可以使用ThreadLocal,这将极大地简化你的程 序,使程序更加易读、简洁。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
五.参考
大多数内容都是以下3个网址的内容,然后对其中的一些例子加上自己的理解,有意见或者建议欢迎指出。
- http://lavasoft.blog.51cto.com/62575/51926/
- http://justsee.iteye.com/blog/791919
- http://blog.csdn.net/abing37/article/details/4460298
- ThreadLocal 多线程同步关键字
- Java 多线程:ThreadLocal 多线程同步关键字
- Java 多线程:ThreadLocal关键字
- 多线程(六):ThreadLocal 关键字
- volatile 多线程同步关键字
- ThreadLocal实现局部变量的多线程同步
- Java多线程之同步关键字
- Java多线程同步 synchronized关键字
- android 多线程同步-synchronized关键字
- Java 多线程:volatile 多线程同步关键字
- Java 多线程:Condition 多线程同步关键字
- Java 多线程:volatile 多线程同步关键字
- Java 多线程:synchronized 多线程同步关键字
- Java 多线程:Condition 多线程同步关键字
- Java 多线程:synchronized 多线程同步关键字
- Java——多线程总结、ThreadLocal/Volatile/synchronized/Atomic关键字
- java多线程编程关键字volatile,ThreadLocal和synchronized
- Java多线程技术研究(二)-线程同步,通信及ThreadLocal
- PowerBuilder创建与释放对象实例
- Android实践之ScrollView中滑动冲突处理
- NOIP2006普及组复赛试题 1.明明的随机数(桶排序,冒泡排序,快速排序)
- iPhone彻底删除itunes程序列表中的应用
- U盘安装centos6.5
- ThreadLocal 多线程同步关键字
- HDU1011——Starship Troopers(树状dp)
- vs2013 中localdb 的使用(2)
- 台大机器学习基石作业编程题
- nginx支持yaf的path_info配置
- linux userdel
- 关于spring、pringmvc整合时注解扫描
- hdu1503 Advanced Fruits (LCS)
- db2数据插入错误SQL0000W