ThreadLocal简单学习
来源:互联网 发布:淘宝充300抢150的攻略 编辑:程序博客网 时间:2024/06/11 12:25
学习Struts2时,遇到ThreadLocal,不甚理解,所以对此作了一番学习。
ThreadLocal是什么呢?首先这并不是一个线程类,它是用来提供本地线程数据,也就是它保存的数据是线程相关的,每个线程都有一份数据副本,一个线程可以对其保存的副本进行修改,却不会影响其它的线程中的数据。这样说不易理解,比较这三种情况的数据,1、非ThreadLocal类型的静态成员数据;2、非ThreadLocal类型的非静态成员数据;3、ThreadLocal类型的静态数据。第一种情况中的数据是类类型的,所以此变量是所有线程共享的,第二种情况中的数据是实例对象相关的数据,是线程相关的,不同线程中实例数据的修改是相互不影响的。第三种虽然是静态类型的数据,但是由于是通过ThreadLocal保存的,所以还是线程相关的。由第三种类型的数据和第一种类型的数据之间的对比,可以帮助了解ThreadLocal的功能。
ThreadLocal的接口功能比较简单,常用的为get、set、remove,它们的函数签名如下
get接口public T get();
set接口public void set(T);
remove接口public void remove();
下面用一个简单的项目来说明ThreadLocal的功能。项目内容很简单,主要包括三个类TestThread、Main和TestClass
TestClass.java代码如下
import java.util.Random;
public class TestClass {
private static int value=0;
public int nonStaticValue ;
private static ThreadLocal<Integer> threadLocalValue= new ThreadLocal<Integer>();
public TestClass(){
Random rand= new Random();
nonStaticValue =rand.nextInt(100);
value ++;
}
public static Integer getLocalThreadValue(){
return threadLocalValue .get();
}
public static void setLocalThreadValue(Integer val){
threadLocalValue .set(val);
}
public static int getStaticValue(){
return value ;
}
public int getNonStaticValue(){
return nonStaticValue ;
}
}
TestThread.java代码如下
public class TestThread extends Thread {
private int id ;
TestClass clz;
public TestThread( int id) {
super ("thread-" +id);
this .id = id;
System. out .println("thread in test thread constructor "
+ Thread. currentThread().getName());
}
@Override
public void run() {
TestClass. setLocalThreadValue( id);
clz = new TestClass();
int maxRuntime=2000;
int step=1000;
int totalRuntime=0;
while (totalRuntime<maxRuntime) {
totalRuntime+=step;
System. out .println(Thread.currentThread().getName() + "[non-static-value:"
+ clz.getNonStaticValue() + ",static-value:"
+ TestClass. getStaticValue() + ",thread local value:"
+ TestClass. getLocalThreadValue() + "]");
try {
Thread. sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Main.java代码如下
public class Main extends Thread{
public int num ;
public Main(String name, int num){
super (name);
this .num =num;
}
@Override
public void run(){
for (int i=0;i<3;i++){
try {
Thread. sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num++;
System. out .println(Thread.currentThread().getName()+ "[ num = "+ num+ " ]");
}
}
public static void main(String[] args) {
int num=3;
TestThread[] threads= new TestThread[num];
for (int i=0;i<num;i++){
threads[i]= new TestThread(i);
}
for (int i=0;i<num;i++){
threads[i].start();
}
System. out .println("--------------------------------------+\t\r" );
num=2;
Main[] mains= new Main[num];
for (int i=0;i<num;i++){
mains[i]= new Main("main thread" +i,i);
}
for (int i=0;i<num;i++)
mains[i].start();
}
}
运行之后的输出结果如下
thread in test thread constructor main
thread in test thread constructor main
thread in test thread constructor main
--------------------------------------
thread-0[non-static-value:26,static-value:3,thread local value:0]
thread-1[non-static-value:49,static-value:3,thread local value:1]
thread-2[non-static-value:59,static-value:3,thread local value:2]
main thread0[ num = 1 ]
main thread1[ num = 2 ]
thread-0[non-static-value:26,static-value:3,thread local value:0]
thread-1[non-static-value:49,static-value:3,thread local value:1]
thread-2[non-static-value:59,static-value:3,thread local value:2]
main thread0[ num = 2 ]
main thread1[ num = 3 ]
main thread0[ num = 3 ]
main thread1[ num = 4 ]
看其中的输出,非静态的成员变量(私有或公有)是线程相关的,静态的类变量是多个线程共享的,而由静态的ThreadLocal对象保存的数据,依旧是线程相关的,各个线程之间的值是有区别的。
[ThreadLocal的实现原理]
要理解ThreadLocal的实现原理,需要了解ThreadLocalMap类。TThreadLocalMap有一个Entry类型的数组,每个Entry是一个<ThreadLocal,Object>的键值对,在数组中的索引由ThreadLocal对象的哈希值和当前数组的长度值减一做与操作而来,如果出现冲突,就往后查找。ThreadLocalMap类中插入键值对数据的set方法如下所示
private void set(ThreadLocal key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); //首先获取数组索引值
/*
从计算出来的索引点开始比较,如果能找到相应的key,就更新值
*/
for (Entry e = tab[i];
e != null ;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
if (k == key) {
e.value = value;
return ;
}
if (k == null ) {
replaceStaleEntry(key, value, i);
return ;
}
}
tab[i] = new Entry(key, value); //没有找到相应的key,插入新数据
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
每个Thread类型的线程都有个ThreadLocalMap类型的实例变量threadlocals,用来存放与此线程相关的ThreadLocal变量。再来看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);
}
首先获取当前的线程t,由getMap方法获取当前线程的threadLocals属性map,然后保存键值对。在保存的时候采用this对象做为键,同样在获取数据的时候,也是以this作为键来获取相应的数据。因为一个线程可能有多个由ThreadLocal对象保存的变量,采用this作为key,可以实现这样不同ThreadLocal对象之间的区分。
- ThreadLocal简单学习
- ThreadLocal简单的学习和理解过程
- 学习ThreadLocal
- ThreadLocal 学习
- ThreadLocal学习
- ThreadLocal学习
- ThreadLocal 学习
- ThreadLocal学习
- ThreadLocal 学习
- ThreadLocal学习
- ThreadLocal学习
- ThreadLocal 学习
- ThreadLocal 学习
- ThreadLocal学习
- 学习ThreadLocal
- 学习ThreadLocal
- ThreadLocal学习
- ThreadLocal学习
- 动态规划题 UVA Prince and Princess
- itk copy a image
- [CSS]为什么不推荐在CSS中使用ID选择器
- POJ2184-Cow Exhibition
- Eclipse快捷键
- ThreadLocal简单学习
- hdoj_1004 Let the Balloon Rise
- UvaLive-2191-Potentiometers
- Oracle OCP 培训笔记(2013年4月21日)
- 任务规划
- hdu 1542(线段树 求矩形面积并)Atlantis
- 因为追新,好奇,使有myeclipse 2013过程中发现的问题及解决办法
- Hough变换 直线检测原理及其Matlab实现
- JQuery效果展示--不看后悔N辈子