一、java.lang.ThreadLocal<T>
理解:
一个ThreadLocal是一个中介或者工具,来完成这样的目标,一个线程关联一个数据,在线程内共享该数据。
然后通过ThreadLocal对象,和当前线程对象,可以唯一设置一个数据,获取该数据。
其实每一个线程内部都有一个容器ThreadLocalMap,类似于一个Map,存储key-value值。
这里的value就是数据,这里的key是ThreadLocal对象。
ThreadLocal实例 | 线程T1 | 线程T2 | 线程T3 |
tl1 | tl1:value1 | tl1:value1 | |
tl2 | tl2:value2 | tl2:value2 |
二、ThreadLocal有这样几个方法:
1.T get()
返回当前线程、当前ThreadLocal对象对应的那个数据。
实现是以ThreadLocal对象为Key去当前线程的容器map中去找数据,找到则返回;找不到则初始化一个,set进去,然后返回。
2.void set(T value)
给当前线程,当前ThreadLocal对象关联一个数据。
实现是以ThreadLocal对象为KEY,变量为VALUE存储到当前线程的map属性中去。
3.protected T initialValue()
get方法再找不到当前线程对应的变量时调用这个方法,用于初始化一个变量的值,默认是返回null。可以写一个子类继承ThreadLocal类,重写这个方法以返回需要的值。
4.void remove()
删除当前线程对应的变量
实现是删除map属性中当前线程的KEY-VALUE数据。
--------------------------------------------------------------------------------------------------------------
三、另一个思路实现该功能:
package tp.t1; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class ThreadLocal{ //map属性,用于存储线程对象和变量的对应数据 private Map values = Collections.synchronizedMap(new HashMap()); //返回当前线程对应的那个变量 public Object get(){ Thread curThread = Thread.currentThread(); Object o = values.get(curThread); if (o == null && !values.containsKey(curThread)){ o = initialValue(); values.put(curThread, o); } return o; } //给当前线程关联一个变量 public void set(Object newValue){ values.put(Thread.currentThread(), newValue); } //初始化一个变量的值 public Object initialValue(){ return null; } }
四、测试
- 测试1
package tp.t1; import tp.t1.SequenceNumber; import tp.t1.TestThread; import java.lang.ThreadLocal; public class Test1 { /* * 起两个线程 * 每个线程给自己在ThreadLocal实例t1中关联的变量加1后显示出来,循环3次。 * 看看每个线程的值会不会互相影响? * 答案是不会影响,每个线程关联的是自己的变量 */ public static void main(String[] args){ Thread _t1 = new TestThread(); Thread _t2 = new TestThread(); _t1.start(); _t2.start(); } } class SequenceNumber { //只需要一个ThreadLocal实例,这里定义在一个类的静态属性中,在各个线程中可以直接访问到。 private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>(){ public Integer initialValue(){ return 0; } }; //定义一个方法,用于各个线程给自己关联的变量值加1 public static int getNextNum(){ SequenceNumber.tl.set(SequenceNumber.tl.get() + 1); return SequenceNumber.tl.get(); } } class TestThread extends Thread{ public void run(){ for(int i = 0;i < 3;i++){ int _num = SequenceNumber.getNextNum(); System.out.println("Thread["+Thread.currentThread().getName()+"]-num["+_num+"]"); } } }
Thread[Thread-0]-num[1]
Thread[Thread-1]-num[1]
Thread[Thread-0]-num[2]
Thread[Thread-1]-num[2]
Thread[Thread-0]-num[3]
Thread[Thread-1]-num[3]
- 测试2
package tp.t2; import java.lang.ThreadLocal; public class Test2 { /* * 起两个线程 * 每个线程在各自关联的变量是同一个实例,这时每个线程修改实例的内容,输出实例的内容。 * 看看每个线程在ThreadLocal对象中,关联的变量是不是copy出来的副本,是不是会互不影响? * 答案是各个线程如果关联同一个变量,那么一个线程修改变量后,另一个线程关联的变量也变化了。 */ public static void main(String[] args){ //一个ThreadLocal实例,存储的变量时AnObject类型的实例 ThreadLocal<AnObject> _tl = new ThreadLocal<AnObject>(){ public AnObject initialValue(){ return new AnObject(); } }; //一个AnObject类型的实例 AnObject _anObj = new AnObject(); _anObj.s = Thread.currentThread().getName(); //关联当前主线程和这个变量 _tl.set(_anObj); System.out.println("Thread["+Thread.currentThread().getName()+"]-string["+_tl.get().s+"]"); //起的第一个线程,修改变量的内容,关联变量 Thread _t1 = new TestThread(_tl,_anObj); _t1.start(); //起的第二个线程,修改变量的内容,关联变量 Thread _t2 = new TestThread(_tl,_anObj); _t2.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } //输出最后这个变量的内容 System.out.println(_anObj.s); } } class TestThread extends Thread{ private ThreadLocal<AnObject> tl; private AnObject anObj; public TestThread(ThreadLocal<AnObject> _tl,AnObject _anObj){ this.tl = _tl; this.anObj = _anObj; this.anObj.s = this.getName(); //放在这里去关联是不可以的,因为这里的Thread.currentThread()是主线程 //this.tl.set(this.anObj); } public void run(){ //当前线程关联变量 this.tl.set(this.anObj); System.out.println("Thread["+this.getName()+"]-string["+this.tl.get().s+"]"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread["+this.getName()+"]-string["+this.tl.get().s+"]"); } } class AnObject extends Object{ String s = ""; }
Thread[main]-string[main]
Thread[Thread-0]-string[Thread-1]
Thread[Thread-1]-string[Thread-1]
Thread[Thread-0]-string[Thread-1]
Thread[Thread-1]-string[Thread-1]
Thread-1
相关推荐
关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. ...
主要介绍ThreadLocal的原理,实例分析以及注意事项
主要介绍了彻底理解Java 中的ThreadLocal的相关资料,需要的朋友可以参考下
主要介绍了Android 中 ThreadLocal使用示例的相关资料,这里提供示例代码帮助大家学习理解这部分内容,需要的朋友可以参考下
主要介绍了Java ThreadLocal用法,结合实例形式详细分析了ThreadLocal线程局部变量相关原理、定义与使用方法,需要的朋友可以参考下
主要介绍了Android 中ThreadLocal的深入理解的相关资料,希望通过本文能帮助到大家,让大家理解应用ThreadLocal,需要的朋友可以参考下
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。使用这个工具类可以很简洁地编写出优美的多线程程序。接下来通过本文给大家介绍Java中的ThreadLocal,需要的朋友可以参考下
主要介绍了java 中ThreadLocal 的正确用法的相关资料,需要的朋友可以参考下
主要介绍了Java 并发编程之ThreadLocal详解及实例的相关资料,需要的朋友可以参考下
主要介绍了从面试中的问题分析ThreadLocal,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起学习一下吧
主要介绍了ThreadLocal使用案例分析,需要的朋友可以参考下
主要介绍了Java ThreadLocal类应用,结合具体案例形式分析了java ThreadLocal类的功能、原理、用法及相关操作注意事项,需要的朋友可以参考下
主要为大家详细介绍了java ThreadLocal的使用案例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
主要介绍了关于ThreadLocal对request和response的用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date...介绍ThreadLocal使用demoThreadLocal源码探索ThreadLocal注意事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...
主要介绍了ThreadLocal原理及内存泄漏原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了深入理解ThreadLocal工作原理及使用示例,涉及ThreadLocal<T> 简介和使用示例及ThreadLocal的原理等相关内容,具有一定参考价值,需要的朋友可以了解下。
主要介绍了java 中ThreadLocal实例分析的相关资料,需要的朋友可以参考下
主要介绍了Java ThreadLocal的设计理念与作用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
目录一、背景介绍二、TestNG多线程详解2.1 TestNG多线程实现2.2 TestNG多线程效果演示三、ThreadLocal3.1 ThreadLocal概念3.2 具体实现 一、背景介绍 在使用Selenium+TestNG做WebUI自动化过程中,为了能够加快Web...