使用ThreadLocal变量的时机和方法
2015-11-16 11:39
309 查看
并发编程中,一个重要的内容是数据共享。当你创建了实现Runnable接口的线程,然后开启使用相同Runnable实例的各种Thread对象,所有 的线程便共享定义在Runnable对象中的属性。也就是说,当你在一个线程中改变任意属性时,所有的线程都会因此受到影响,同时会看到第一个线程修改后的值。有时我们希望如此,比如:多个线程增大或减小同一个计数器变量;但是,有时我们希望确保每个线程,只能工作在它自己的线程实例的拷贝上,同时不会影 响其他线程的数据。
举个例子,想象你在开发一个电子商务应用,你需要为每一个控制器处理的顾客请求,生成一个唯一的事务ID,同时将其传到管理器或DAO的业务方法中,以便记录日志。一种方案是将事务ID作为一个参数,传到所有的业务方法中。但这并不是一个好的方案,它会使代码变得冗余。
你可以使用ThreadLocal类型的变量解决这个问题。首先在控制器或者任意一个预处理器拦截器中生成一个事务ID,然后在ThreadLocal中 设置事务ID,最后,不论这个控制器调用什么方法,都能从threadlocal中获取事务ID。而且这个应用的控制器可以同时处理多个请求,同时在框架 层面,因为每一个请求都是在一个单独的线程中处理的,所以事务ID对于每一个线程都是唯一的,而且可以从所有线程的执行路径获取。
扩展阅读:与JAX-RS
ResteasyProviderFactory共享上下文数据(ThreadLocalStack实例)
Java并发API为使用ThreadLocal类的局部线程变量提供了一个简洁高效的机制,
这个类提供了一个局部线程变量。这些变量不同于其所对应的常规变量,对于常规变量,每个线程只能访问(通过get或set方法)其自身所拥有的,独立初始化变量拷贝。在一个类中,ThreadLocal类型的实例是典型的私有、静态(private
static)字段,因为我们可以将其作为线程的关联状态(比如:用户ID或者事务ID)
这个类有以下方法:
get():返回当前线程拷贝的局部线程变量的值。
initialValue():返回当前线程赋予局部线程变量的初始值。
remove():移除当前线程赋予局部线程变量的值。
set(T value):为当前线程拷贝的局部线程变量设置一个特定的值。
下面的例子使用两个局部线程变量,即threadId和startDate。它们都遵循推荐的定义方法,即“private static”类型的字段。threadId用来区分当前正在运行的线程,startDate用来获取线程开启的时间。上面的信息将打印到控制台,以此验 证每一个线程管理他自己的变量拷贝。
现在要验证变量本质上能够维持其自身状态,而与多线程的多次初始化无关。我们首先需要创建执行这个任务的三个线程,然后开启线程,接着验证它们打印到控制台中的信息。
在上面的输出中,打印出的声明序列每次都在变化。我已经把它们放到了序列中,这样对于每一个线程实例,我们都可以清楚地辨别出,局部线程变量保持着安全状态,而绝不会混淆。自己尝试下!
局部线程通常使用在这样的情况下,当你有一些对象并不满足线程安全,但是你想避免在使用synchronized关键字、块时产生的同步访问,那么,让每个线程拥有它自己的对象实例。
注意:局部变量是同步或局部线程的一个好的替代,它总是能够保证线程安全。唯一可能限制你这样做的是你的应用设计约束。
警告:在webapp服务器上,可能会保持一个线程池,那么ThreadLocal变量会在响应客户端之前被移除,因为当前线程可能被下一个请求重复使用。而 且,如果在使用完毕后不进行清理,它所保持的任何一个对类的引用—这个类会作为部署应用的一部分加载进来—将保留在永久堆栈中,永远不会被垃圾回收机制回收。
学习愉快!
原文链接: howtodoinjava 翻译: ImportNew.com - Angus
译文链接: http://www.importnew.com/14398.html
[ 转载请保留原文出处、译者和译文链接。]
使用ThreadLocal的时机
举个例子,想象你在开发一个电子商务应用,你需要为每一个控制器处理的顾客请求,生成一个唯一的事务ID,同时将其传到管理器或DAO的业务方法中,以便记录日志。一种方案是将事务ID作为一个参数,传到所有的业务方法中。但这并不是一个好的方案,它会使代码变得冗余。你可以使用ThreadLocal类型的变量解决这个问题。首先在控制器或者任意一个预处理器拦截器中生成一个事务ID,然后在ThreadLocal中 设置事务ID,最后,不论这个控制器调用什么方法,都能从threadlocal中获取事务ID。而且这个应用的控制器可以同时处理多个请求,同时在框架 层面,因为每一个请求都是在一个单独的线程中处理的,所以事务ID对于每一个线程都是唯一的,而且可以从所有线程的执行路径获取。
扩展阅读:与JAX-RS
ResteasyProviderFactory共享上下文数据(ThreadLocalStack实例)
ThreadLocal类
Java并发API为使用ThreadLocal类的局部线程变量提供了一个简洁高效的机制,static)字段,因为我们可以将其作为线程的关联状态(比如:用户ID或者事务ID)
这个类有以下方法:
get():返回当前线程拷贝的局部线程变量的值。
initialValue():返回当前线程赋予局部线程变量的初始值。
remove():移除当前线程赋予局部线程变量的值。
set(T value):为当前线程拷贝的局部线程变量设置一个特定的值。
怎样使用ThreadLocal?
下面的例子使用两个局部线程变量,即threadId和startDate。它们都遵循推荐的定义方法,即“private static”类型的字段。threadId用来区分当前正在运行的线程,startDate用来获取线程开启的时间。上面的信息将打印到控制台,以此验 证每一个线程管理他自己的变量拷贝。局部线程通常使用在这样的情况下,当你有一些对象并不满足线程安全,但是你想避免在使用synchronized关键字、块时产生的同步访问,那么,让每个线程拥有它自己的对象实例。
注意:局部变量是同步或局部线程的一个好的替代,它总是能够保证线程安全。唯一可能限制你这样做的是你的应用设计约束。
警告:在webapp服务器上,可能会保持一个线程池,那么ThreadLocal变量会在响应客户端之前被移除,因为当前线程可能被下一个请求重复使用。而 且,如果在使用完毕后不进行清理,它所保持的任何一个对类的引用—这个类会作为部署应用的一部分加载进来—将保留在永久堆栈中,永远不会被垃圾回收机制回收。
学习愉快!
原文链接: howtodoinjava 翻译: ImportNew.com - Angus
译文链接: http://www.importnew.com/14398.html
[ 转载请保留原文出处、译者和译文链接。]
相关文章推荐
- 循环队列
- LoadRunner错误处理函数
- 第四天-secureCRT-ssh客户端使用详解
- 微软云的新体验,azure remoteIE(私用)
- 仿滴滴打车底部滑动条代码逻辑实现
- 完美网络
- orcle 序列
- windows下安装pip
- 数据结构、算法与应用 (C++描述) 第二版 1.16
- Linux下FTP服务器搭建
- libc++abi.dylib: terminate_handler unexpectedly threw an exception错误小结
- Date类型数据转化json后,在jsp获取日期显示为[object Object]问题
- cocos2dx 2.2.6的2个js相关的错误--bad script XDR magic number
- 多项式求和
- TNS-12555 permission denied
- -canOpenURL: failed for URL: "" - error: "(null)" , iOS9 App传输安全 支持http 解决方案
- MeasureSpec 的三中类型
- 利用JS提交表单的几种方法和验证
- Git和Code Review流程
- 算术表达式的转换