`
wobfei
  • 浏览: 146983 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ThreadLocal使用介绍

阅读更多

首先有几点需要大家清楚的:

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的使用方法以及作用。

如果要深入使用,建议还是看下源码吧

 

分享到:
评论
2 楼 treemanfm 2014-07-23  
卖火柴的老特工 写道
你在run方法里声明了MyThreadLocal local一个局部变量,这样的效果和在run方法里新建一个user对象和timeconsumer对象实现有区别吗?抱歉,没看明白啊,求指点


可能你没看到 MyThreadLocal是一个单例,若被多个线程访问的话,会产生冲突。使用了ThreadLocal线程本地变量后,每个线程中都持有自己的user对象和timeconsumer对象,就避免冲突了。
1 楼 卖火柴的老特工 2013-12-03  
你在run方法里声明了MyThreadLocal local一个局部变量,这样的效果和在run方法里新建一个user对象和timeconsumer对象实现有区别吗?抱歉,没看明白啊,求指点

相关推荐

Global site tag (gtag.js) - Google Analytics