ThreadLocal使用介绍
首先有几点需要大家清楚的:
1、 ThreadLocal只是对需要存储的对象的管理,而存储实际是由当前Thread负责。个人理解为ThreadLocal是一个操作Thread. threadLocals 的工具。
2、 使用ThreadLocal可以使对象达到线程隔离的目的。同一个ThreadLocal操作不同的Thread,实质是各个Thread对自己的变量操作。
3、 为什么要使用ThreadLocal,个人感觉有两个原因,1是与其它线程的隔离,2是可以在一个线程的生命周期中使用同一个对象,达到对象传递的作用。这样的好处是可以减少dal访问或者ws调用。
我这里列出一个用到ThreadLocal的例子,主要的作用是使用ThreadLocal记录用户信息以及记录用户的执行时间。这在实际应用中,可以映射为全局记录用户的权限,以及使用Threadlocal对系统的性能做一些分析等。。
首先有两个对象,一个是用户对象
Java代码
-
// 简单记录用户是否可以访问,可以用于全局权限控制等
-
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;
-
}
-
}
另一个是消费时间对象
Java代码
-
// 用于记录每一步骤耗时…,可以用于每一步的性能分析
-
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的类
Java代码
-
// 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进行测试了。为了模拟多线程,我这里自己实现了多线程
Java代码
-
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();
-
}
-
}
-
}
运行上面的程序得到结果如下:
Java代码
-
用户名:name2 是否允许访问:true
-
操作[name2]共有2步
-
|--耗时[703ms]
-
|--耗时[1406ms]
-
-
-
用户名:name3 是否允许访问:false
-
操作[name3]共有2步
-
|--耗时[891ms]
-
|--耗时[1781ms]
-
-
-
用户名:name1 是否允许访问:true
-
操作[name1]共有2步
-
|--耗时[1000ms]
-
|--耗时[2000ms]
通过上面的测试程序,可以大概了解ThreadLocal的使用方法以及作用。
如果要深入使用,建议还是看下源码吧…