javathreadlocal:Java中ThreadLocal的设计和使用

早在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这将极大地简化你使更加易读、简洁
Tags:  java中的设计模式 java中数组的使用 threadlocal javathreadlocal

延伸阅读

最新评论

发表评论