文章目录
线程局部变量 ThreadLocal
ThreadLocal 的作用和目的
- 用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个 线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。
- 每个线程调用全局 ThreadLocal 对象的 set 方法,在 set 方法中,首先根据当前线程获取当前线程的
ThreadLocalMap 对象,然后往这个 map 中插入一条记录,key 其实是 ThreadLocal 对象,value 是各自的 set方法传进去的值。也就是每个线程其实都有一份自己独享的 ThreadLocalMap对象,该对象的 Key 是 ThreadLocal对象,值是用户设置的具体值。在线程结束时可以调用 ThreadLocal.remove()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的 ThreadLocal 变量。
ThreadLocal 的应用场景
-
订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个
事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面
的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码 分别位于不同的模块类中。 -
银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同 的帐户对象的方法。
-
例如 Strut2 的 ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext 方法拿到的对象都不相同,对同一个 线程来说,不管调用 getContext 方法多少次和在哪个模块中 getContext 方法,拿到的都是同一 个。
ThreadLocal 的使用方式
(1) 在关联数据类中创建 private static ThreadLocal
在下面的类中,私有静态 ThreadLocal 实例(serialNum)为调用该类的静态 SerialNum.get() 方法的每个线程维护了一个“序列号”,该方法将返回当前线程的序列号。(线程的序列号是在第一次调用 SerialNum.get() 时分配的,并在后续调用中不会更改。)
package com.wjl.test.mythreadLocal;
public class SerialNum {
//The next serial number to be assigned
private static int nextSerialNum=0;
private static ThreadLocal serialNum=new ThreadLocal(){
protected synchronized Object initialValue(){
return new Integer(nextSerialNum++);
}
};
public static int get(){
return ((Integer)(serialNum.get())).intValue();
}
public static void main(String[] args) {
System.out.println(get());//0
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"serialNum = "+get());
}
}).start();