首先有几点需要大家清楚的:
1、 ThreadLocal只是对需要存储的对象的管理,而存储实际是由当前Thread负责。个人理解为ThreadLocal是一个操作Thread. threadLocals 的工具。
2、 使用ThreadLocal可以使对象达到线程隔离的目的。同一个ThreadLocal操作不同的Thread,实质是各个Thread对自己的变量操作。
3、 为什么要使用ThreadLocal,个人感觉有两个原因,1是与其它线程的隔离,2是可以在一个线程的生命周期中使用同一个对象,达到对象传递的作用。这样的好处是可以减少dal访问或者ws调用。
我这里列出一个用到ThreadLocal的例子,主要的作用是使用ThreadLocal记录用户信息以及记录用户的执行时间。这在实际应用中,可以映射为全局记录用户的权限,以及使用Threadlocal对系统的性能做一些分析等。。
首先有两个对象,一个是用户对象
// 简单记录用户是否可以访问,可以用于全局权限控制等
class User {
private String name;
private boolean isAllow;
public User(String name, boolean isAllow) {
this.name = name;
this.isAllow = isAllow;
}
public String getName() {
return name;
}
public boolean isAllow() {
return isAllow;
}
@Override
public String toString() {
return "用户名:" + name + "\t 是否允许访问:" + isAllow;
}
}
另一个是消费时间对象
// 用于记录每一步骤耗时…,可以用于每一步的性能分析
class TimeConsumer {
// 名称
private String name;
// 耗时数据列表
private List<Long> steps;
public TimeConsumer(String name, long start) {
this.name = name;
steps = new ArrayList<Long>();
steps.add(start);
}
public void andStep(long step) {
steps.add(step);
}
@Override
public String toString() {
StringBuffer br = new StringBuffer("操作[" + name + "]共有"
+ (steps.size() - 1) + "步\n");
for (int i = 1; i < steps.size(); i++) {
br.append("\t|--耗时[" + (steps.get(i) - steps.get(0))
+ "ms]\n");
}
br.append("\n");
return br.toString();
}
}
接下来,建立一个对这两个对象管理的ThreadLocal的类
// threadlocal 管理类
class MyThreadLocal {
// 用于全局记录user访问权限
private ThreadLocal<User> userLocal;
// 用于全局记录用户每一步的耗时
private ThreadLocal<TimeConsumer> timeLocal;
private static MyThreadLocal local = new MyThreadLocal();
private MyThreadLocal() {
userLocal = new ThreadLocal<User>();
timeLocal = new ThreadLocal<TimeConsumer>();
}
public static MyThreadLocal getInstanse() {
return local;
}
public void addUser(User user) {
userLocal.set(user);
}
public User getUser() {
return userLocal.get();
}
public void addTime(TimeConsumer timeConsumer) {
timeLocal.set(timeConsumer);
}
public void addTime(long l) {
TimeConsumer time = timeLocal.get();
timeLocal.remove();
time.andStep(l);
timeLocal.set(time);
}
public TimeConsumer getTime() {
return timeLocal.get();
}
}
接下来就可以对Threadlocal进行测试了。为了模拟多线程,我这里自己实现了多线程
public class CoreThreadLocal {
public static void main(String[] args) {
new Thread(new TestRunnable("name1", 1000L, true)).start();
new Thread(new TestRunnable("name2", 700L, true)).start();
new Thread(new TestRunnable("name3", 888, false)).start();
}
}
// 用于测试,多线程实现
class TestRunnable implements Runnable {
String name;
long l;
boolean isAllow;
TestRunnable(String name, long l, boolean isAllow) {
this.name = name;
this.l = l;
this.isAllow = isAllow;
}
public void run() {
MyThreadLocal local = MyThreadLocal.getInstanse();
local.addUser(new User(name, isAllow));
local.addTime(new TimeConsumer(name, System.currentTimeMillis()));
// 做某个业务,并记录时间
doThings(l);
local.addTime(System.currentTimeMillis());
// 做某个业务,并记录时间
doThings(l);
local.addTime(System.currentTimeMillis());
// 业务做完,打印日志
System.out.println(local.getUser());
System.out.println(local.getTime());
}
// 模拟具体业务的处理步骤
private void doThings(long l) {
try {
Thread.sleep(l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行上面的程序得到结果如下:
用户名:name2 是否允许访问:true
操作[name2]共有2步
|--耗时[703ms]
|--耗时[1406ms]
用户名:name3 是否允许访问:false
操作[name3]共有2步
|--耗时[891ms]
|--耗时[1781ms]
用户名:name1 是否允许访问:true
操作[name1]共有2步
|--耗时[1000ms]
|--耗时[2000ms]
通过上面的测试程序,可以大概了解ThreadLocal的使用方法以及作用。
如果要深入使用,建议还是看下源码吧…