首先有几点需要大家清楚的:
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的使用方法以及作用。
如果要深入使用,建议还是看下源码吧…