Java学习笔记——并发之ThreadLocal
来源:互联网 发布:淘宝新店手机号码采集 编辑:程序博客网 时间:2024/06/10 16:29
ThreadLocal是一种线程本地存储机制,可以为使用相同变量的每个不同线程都创建不同的存储。因此,如果你有5个线程都要使用变量x锁表示的对象,线程本地存储就会产生5个用于x的不同存储块。
1. ThreadLocal的用法
ThreadLocal在是泛型类,可以使用set方法设置变量的值,使用get方法获取变量值,示例代码如下:
public class ThreadLocalTest {private final static class TimeCounter{private static ThreadLocal<Long> startTime = new ThreadLocal<Long>();private static void start(String name){startTime.set(System.currentTimeMillis());System.out.println(name + " start time is " + startTime.get());}private static void end(String name){if(startTime.get() == null){return;}System.out.println(name + " start time is " + startTime.get());System.out.println(name + " execute time is " + (System.currentTimeMillis() - startTime.get()));}}private static void doSomthing(String name, long sleepTime){TimeCounter.start(name);sleep(sleepTime);TimeCounter.end(name);}private static void sleep(long sleepTime) {try {Thread.sleep(sleepTime);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {doSomthing("t1", 10000);}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {sleep(5000);doSomthing("t2", 20000);}});t1.start();t2.start();}}上述代码是ThreadLocal的一种典型应用场景:在上下文中不方便直接传递参数(本代码中的startTIme)时,可以在一个方法中将参数保存到ThreadLocal中,再在另一方法中取出使用。本示例代码实现了一个简单的执行时间监测的功能,用于监测代码执行的性能,分别计算线程t1 和 线程t2的执行时间,执行结果如下:
t1 start time is 1512482050827t2 start time is 1512482055834t1 start time is 1512482050827t1 execute time is 10011t2 start time is 1512482055834t2 execute time is 20002可以看出变量startTIme在线程t1和线程t2中是独立的,两个线程的startTIme相互不影响。总结一下,ThreadLocal的使用方法:先初始化,然后使用set和get分别设置和获取值。伪代码如下:
ThreadLocal<T> x = new ThreadLocal<T>();....x.set(t);...x.get();
2.ThreadLocal源码解析
在介绍THreadLocal的源码之前先说明一下:Thread类有一个类型为ThreadLocalMap的成员变量threadLocals,用于存储当前线程的本地变量。定义如下:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;其中,ThreadLocalMap是ThreadLocal的内部类,是以数组存储数据的Key-value的Map(没有实现map接口)。ThreadLocal的set方法的源码如下:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }set方法先从当前线程中获取threadLocals成员变量,如果为空则创建一个ThreadLocalMap并赋给当前线程的threadLocals。从上述代码可以看出,threadLocals的key为this指针,即当前调set方法的ThreadLocal变量。
同样的,get方法也是先从当前线程中取得threadLocals成员变量,然后用this指针作为Key获取当前线程中的ThreadLocal变量.的值。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }3. ThreadLocal的注意事项
在使用线程池的场景下,由于线程执行完成后回归到线程池时,线程的threadLocals变量并不会被重置,因此当这个线程再次执行新任务时,原来的threadLocals的数据仍然存在,因此可能会影响当前任务执行的结果,示例代码如下;
public class TreadTest {public static void main(String[] args) {ThreadLocal<Integer> num = new ThreadLocal<Integer>();ExecutorService executor = Executors.newSingleThreadExecutor();Runnable t1 = new Runnable() {@Overridepublic void run() {System.out.println("thread 1: before set num is:" + num.get());num.set(1);System.out.println("thread 1: after set num is:" + num.get());}};Runnable t2 = new Runnable() {@Overridepublic void run() {System.out.println("thread 2: before set num is:" + num.get());num.set(2);System.out.println("thread 2: after set num is:" + num.get());}};executor.submit(t1);executor.submit(t2);}}执行结果如下所示;
thread 1: before set num is:nullthread 1: after set num is:1thread 2: before set num is:1thread 2: after set num is:2由于线程池里只有1个线程,虽然t1和t2是同时提交线程池的,但是必须等t1执行完成之后再执行t2,并且是线程池中的同一个线程执行的,因此执行t2时num的初始值变成了t1设置后的值,而不是null了,因此在使用ThreadLocal时,最好先初始化再使用。
另外,子线程会继承父线程的ThreadLocal变量。
阅读全文
0 0
- Java学习笔记——并发之ThreadLocal
- JAVA并发学习之ThreadLocal
- Java并发笔记五——ThreadLocal
- JAVA并发--ThreadLocal学习之路
- java并发之ThreadLocal
- Java并发之ThreadLocal
- java并发之ThreadLocal
- Java并发编程—ThreadLocal
- Java 并发编程深入学习——ThreadLocal 原理分析
- Java并发学习之ThreadLocal使用及原理介绍
- 【Java并发编程实践】— ThreadLocal分析
- 【Java并发编程实践】— ThreadLocal分析
- java之ThreadLocal笔记
- Java学习笔记——并发之synchronized
- JAVA并发编程学习笔记之ReentrantLock—推荐-mark
- Java 之 ThreadLocal学习
- java 之 ThreadLocal学习
- [Java并发包学习七]解密ThreadLocal
- bzoj 2667 [cqoi2012]模拟工厂
- Java 笔记 之 变量和常量
- const形参,何时创建临时变量
- poj 2591 Set Definition
- 创建类Student和对象
- Java学习笔记——并发之ThreadLocal
- (3)qt信号与槽的使用(以运行界面为例)
- JavaFX初探与MediaPlayer(2)
- 粒子物理前传:使用Spark统计能谱数据
- Java 找不到或无法加载主类
- 对文本内容进行关键词过滤
- python学习—Day37—redis的hash类型及其他常用类型
- 变量作用域-python
- 计算机网络系列(8)之应用场景Web acceleration