java多线程--ThreadLocal类
2015-12-14 14:30
531 查看
1. ThreadLocal类的实现原理
ThreadLocal类是java中一种解决多线程环境下并发问题的新思路,它的原理就是为每一个线程提供一个变量的副本,这样每个线程对变量的修改就不会影响其他线程。
首先看一下ThreadLocal提供的API:
然后看一下ThreadLocal是怎么为每一个线程提供一个副本的:
public T get(){
Thread t = Thread.currentThread();
ThreadLoclMap map = getMap(t);
if(map != null){
ThreadLocalMap.Entry e = map.getEntry(this); //this 指当前的ThreadLocal
if(e != null)
return (T)e.value;
}
return setInitialValue();
}
//getMap()实际是获取Thread对象中的一个threadLocals变量,而该变量的类型是一个ThreadLocalMap 。
ThreadLocalMap getMap(Thread t){
return t.threadLocals;
}
在Thread中的threadLocals变量的定义如下:
ThreadLocal.ThreadLocalMap threadLocls = null;
而ThreadLocalMap 实际上是ThreadLocal的一个内部类它的定义如下:
static class ThreadLocalMap{
static class Entry extends WeakReference<ThreadLocal>{
Object value;
Entry(ThreadLocal k, Object v){
super(k);
value = v;
}
}
}
再看一下setInitialValue()的源码实现:
private T setInitialValue(){
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
createMap的实现如下:
void createMap(Thread t, T firstValue){
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
而set()方法实际上就是网当前Thread的ThreadLocalMap类型变量中存值。
从上面的源码可以看出实际上Thread类中有一个ThreadLocalMap类型的变量threadLocals,该变量存储以当前的ThreadLocal对象为key,以要保存的变量的值为value的键值对。而ThreadLocalMap是ThreadLocal的一个内部类,可以把它看做ThreadLocal中的一个Map,当在一个线程中调用ThreadLocal的get方法时,会取得当前线程中的ThreadLocalMap类型变量,如果该变量不为空,且里面有键值对,那么就直接取出该类map中的当前ThreadLocal对象为键锁对应的值,即当前线程中的变量值。如果该变量为空,那么再调用setInitialValue方法为其设置值,前提是重了initialValue方法,如果没有重写该方法,那么默认设置的值为null,如果在new一个ThreadLocal的时候重写了
initialValue方法,在调用setInitialValue就可以取得initialValue的值,现在明白重写initialValue的作用
了吧可以调用set方法设置值,其实设置值得过程就是存储副本的过程归根到底还是靠Thread对象中的类似map功能的ThreadLocalMap类型变量为每个线程存储变量的副本。这样每个线程都存储着一个变量的副本。
2.ThreadLocal的应用实例
public class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class ThreadLocalTest implements Runnable{
private final static ThreadLocal stucentLocal = new ThreadLocal();
public static void main(String[] args) {
ThreadLocalTest tl = new ThreadLocalTest();
Thread t1 = new Thread(tl, "a");
Thread t2 = new Thread(tl, "b");
t1.start();
t2.start();
}
public void run(){
accessStudent();
}
public void accessStudent(){
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + "is running!");
Random r = new Random();
int age = r.nextInt(100);
Student student = getStudent();
student.setAge(age);
System.out.println("thread" + currentThreadName + "first read age is:" + student.getAge());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected Student getStudent(){
Student s = (Student) stucentLocal.get();
if(s == null){
s = new Student();
stucentLocal.set(s);
}
return s;
}
}
输出结果:
a is running!
b is running!
threadafirst read age is:17
threadbfirst read age is:50
可以看出,每个线程都保存自己的student的副本。
ThreadLocal类是java中一种解决多线程环境下并发问题的新思路,它的原理就是为每一个线程提供一个变量的副本,这样每个线程对变量的修改就不会影响其他线程。
首先看一下ThreadLocal提供的API:
然后看一下ThreadLocal是怎么为每一个线程提供一个副本的:
public T get(){
Thread t = Thread.currentThread();
ThreadLoclMap map = getMap(t);
if(map != null){
ThreadLocalMap.Entry e = map.getEntry(this); //this 指当前的ThreadLocal
if(e != null)
return (T)e.value;
}
return setInitialValue();
}
//getMap()实际是获取Thread对象中的一个threadLocals变量,而该变量的类型是一个ThreadLocalMap 。
ThreadLocalMap getMap(Thread t){
return t.threadLocals;
}
在Thread中的threadLocals变量的定义如下:
ThreadLocal.ThreadLocalMap threadLocls = null;
而ThreadLocalMap 实际上是ThreadLocal的一个内部类它的定义如下:
static class ThreadLocalMap{
static class Entry extends WeakReference<ThreadLocal>{
Object value;
Entry(ThreadLocal k, Object v){
super(k);
value = v;
}
}
}
再看一下setInitialValue()的源码实现:
private T setInitialValue(){
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
createMap的实现如下:
void createMap(Thread t, T firstValue){
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
而set()方法实际上就是网当前Thread的ThreadLocalMap类型变量中存值。
从上面的源码可以看出实际上Thread类中有一个ThreadLocalMap类型的变量threadLocals,该变量存储以当前的ThreadLocal对象为key,以要保存的变量的值为value的键值对。而ThreadLocalMap是ThreadLocal的一个内部类,可以把它看做ThreadLocal中的一个Map,当在一个线程中调用ThreadLocal的get方法时,会取得当前线程中的ThreadLocalMap类型变量,如果该变量不为空,且里面有键值对,那么就直接取出该类map中的当前ThreadLocal对象为键锁对应的值,即当前线程中的变量值。如果该变量为空,那么再调用setInitialValue方法为其设置值,前提是重了initialValue方法,如果没有重写该方法,那么默认设置的值为null,如果在new一个ThreadLocal的时候重写了
initialValue方法,在调用setInitialValue就可以取得initialValue的值,现在明白重写initialValue的作用
了吧可以调用set方法设置值,其实设置值得过程就是存储副本的过程归根到底还是靠Thread对象中的类似map功能的ThreadLocalMap类型变量为每个线程存储变量的副本。这样每个线程都存储着一个变量的副本。
2.ThreadLocal的应用实例
public class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class ThreadLocalTest implements Runnable{
private final static ThreadLocal stucentLocal = new ThreadLocal();
public static void main(String[] args) {
ThreadLocalTest tl = new ThreadLocalTest();
Thread t1 = new Thread(tl, "a");
Thread t2 = new Thread(tl, "b");
t1.start();
t2.start();
}
public void run(){
accessStudent();
}
public void accessStudent(){
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + "is running!");
Random r = new Random();
int age = r.nextInt(100);
Student student = getStudent();
student.setAge(age);
System.out.println("thread" + currentThreadName + "first read age is:" + student.getAge());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected Student getStudent(){
Student s = (Student) stucentLocal.get();
if(s == null){
s = new Student();
stucentLocal.set(s);
}
return s;
}
}
输出结果:
a is running!
b is running!
threadafirst read age is:17
threadbfirst read age is:50
可以看出,每个线程都保存自己的student的副本。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树