早在Java 1.2推出的时
Java平台中就引入了
个新
支持:java.lang.ThreadLocal
给我们在编写多线程
时提供了
种新
选择
使用这个工具类可以很简洁地编写出优美
多线程
虽然ThreadLocal非常有用
但是似乎现在了解它、使用它
朋友还不多
ThreadLocal是什么
ThreadLocal并非是
个线程
本地实现版本
它并不是
个Thread
而是thread local variable(线程局部变量)
也许把它命名为ThreadLocalVar更加合适
线程局部变量(ThreadLocal)其实
功用非常简单
就是为每
个使用该变量
线程都提供
个变量值
副本
是每
个线程都可以独立地改变自己
副本
而不会和其它线程
副本冲突
从线程
角度看
就好像每
个线程都完全拥有该变量
线程局部变量并不是Java
新发明
在其它
些语言编译器实现(如IBM XL FORTRAN)中
它在语言
层次提供了直接
支持
Java中没有提供在语言层次
直接支持
而是提供了
个ThreadLocal
类来提供支持
所以
在Java中编写线程局部变量
代码相对比较笨拙
这也许是线程局部变量没有在Java中得到很好
普及
个原因吧
ThreadLocal
设计
首先看看ThreadLocal
接口:
Object get
;
// 返回当前线程
线程局部变量副本 protected Object initialValue
; // 返回该线程局部变量
当前线程
值
void
(Object value);
// 设置当前线程
线程局部变量副本
值
ThreadLocal有3个思路方法
其中值得注意
是initialValue
该思路方法是
个protected
思路方法
显然是为了子类重写而特意实现
该思路方法返回当前线程在该线程局部变量
值
这个思路方法是
个延迟
思路方法
在
个线程第1次
get
或者
(Object)时才执行
并且仅执行1次
ThreadLocal中
确实实现直接返回
个null:
protected Object initialValue
{
null; }
ThreadLocal是如何做到为每
个线程维护变量
副本
呢?其实实现
思路很简单
在ThreadLocal类中有
个Map
用于存储每
个线程
变量
副本
比如下面
举例实现:
public
ThreadLocal
{
private Map values = Collections.synchronizedMap(
HashMap
);
public Object get
{
Thread curThread = Thread.currentThread
;
Object o = values.get(curThread);
(o
null && !values.containsKey(curThread))
{
o = initialValue
;
values.put(curThread, o);
}
o;
}
public void
(Object
Value)
{
values.put(Thread.currentThread
,
Value);
}
public Object initialValue
{
null;
}
}
当然
这并不是
个工业强度
实现
但JDK中
ThreadLocal
实现总体思路也类似于此
ThreadLocal
使用
如果希望线程局部变量
化其它值
那么需要自己实现ThreadLocal
子类并重写该思路方法
通常使用
个内部匿名类对ThreadLocal进行子类化
比如下面
例子
SerialNum类为每
个类分配
个序号
public
SerialNum
{
// The next serial number to be assigned
private
nextSerialNum = 0;
private
ThreadLocal serialNum =
ThreadLocal
{
protected synchronized Object initialValue
{
Integer(nextSerialNum
);
}
};
public
get
{
((Integer) (serialNum.get
)).
Value
;
}
}
SerialNum类
使用将非常地简单
get
思路方法是
所以在需要获取当前线程
序号时
简单地
:
serial = SerialNum.get
;
即可
在线程是活动
并且ThreadLocal对象是可访问
时
该线程就持有
个到该线程局部变量副本
隐含引用
当该线程运行结束后
该线程拥有
所以线程局部变量
副本都将失效
并等待垃圾收集器收集
ThreadLocal和其它同步机制
比较
ThreadLocal和其它同步机制相比有什么优势呢?ThreadLocal和其它所有
同步机制都是为了解决多线程中
对同
变量
访问冲突
在普通
同步机制中
是通过对象加锁来实现多个线程对同
变量
安全访问
这时该变量是多个线程共享
使用这种同步机制需要很细致地分析在什么时候对变量进行读写
什么时候需要锁定某个对象
什么时候释放该对象
锁等等很多
所有这些都是
多个线程共享了资源造成
ThreadLocal就从另
个角度来解决多线程
并发访问
ThreadLocal会为每
个线程维护
个和该线程绑定
变量
副本
从而隔离了多个线程
数据
每
个线程都拥有自己
变量副本
从而也就没有必要对该变量进行同步了
ThreadLocal提供了线程安全
共享对象
在编写多线程代码时
可以把不安全
整个变量封装进ThreadLocal
或者把该对象
特定于线程
状态封装进ThreadLocal
由于ThreadLocal中可以持有任何类型
对象
所以使用ThreadLocal get当前线程
值是需要进行强制类型转换
但随着新
Java版本(1.5)将模版
引入
新
支持模版参数
ThreadLocal类将从中受益
也可以减少强制类型转换
并将
些
检查提前到了编译期
将
定程度地简化ThreadLocal
使用
整理总结
当然ThreadLocal并不能替代同步机制
两者面向
问题领域区别
同步机制是为了同步多个线程对相同资源
并发访问
是为了多个线程的间进行通信
有效方式;而ThreadLocal是隔离多个线程
数据共享
从根本上就不在多个线程的间共享资源(变量)
这样当然不需要对多个线程进行同步了
所以
如果你需要进行多个线程的间进行通信
则使用同步机制;如果需要隔离多个线程的间
共享冲突
可以使用ThreadLocal
这将极大地简化你
使
更加易读、简洁
延伸阅读
最新评论