浅谈ThreadLocal模式
一、前言:
ThreadLocal模式,严格意义上不是一种设计模式,而是java中解决多线程数据共享问题的一个方案。ThreadLocal类是java JDK中提供的一个类,用来解决线程安全问题,并不是线程类。
二、基础:
线程安全:简单来说,指的是在多线程环境中,对类的内部实例变量的访问是安全的。而方法声明中的参数变量以及方法中的内部变量是不存在线程安全问题,因为每个线程独自管理自己方法内部的变量。
三、原理与实现:
1,原理:多个线程访问同一共享变量时,ThreadLocal类为每个线程提供一份该变量的副本,各个线程拥有一份属于自己的变量副本,操作修改的是各自的变量副本,而不会相互影响。
2,看看JDK源码实现,你就会豁然开朗:
(1)Thread类中有一个变量threadLocals,意味着:每个线程有一个自己的变量,这个变量不会给别的线程操作访问,对吧?那么,我们把共享变量的副本,存储在这个变量中,这样就安全了吧?
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
(2)接下来,看看ThreadLocal类是怎么操作这个变量的:
//把value保存在当前线程的本地变量中
public void set(T value) {
Thread t = Thread.currentThread();
//得到当前线程的本地变量
ThreadLocalMap map = getMap(t);
if (map != null)
//以当前的ThreadLocal实例作为Key,把值设进去
map.set(this, value);
else
createMap(t, value);
}
//提取当前线程中以ThreadLocal实例为Key的变量值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
//以当前的ThreadLocal实例作为Key
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return 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;
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
static class ThreadLocalMap {.....}
你有没有看到,多个共享变量,怎么保存在线程的ThreadLocalMap中?以map的形式,那么key是什么?key就是ThreadLocal实例。有多个共享变量的时候,就会创建多个ThreadLocal实例与其对应,同一个线程中,各个共享变量就不会相互干扰。而线程与线程之间,更不会有干扰,每个线程访问的都是自己的ThreadLocalMap。
四、模式的使用:
(1)使用场景:在同一个线程的不同开发层次中共享数据。如web应用开发中表示层、业务层、持久层需要共享数据;
(2)使用步骤:
1)建立一个类,在其中添加一个静态的ThreadLocal变量,使其成为一个共享环境;
2)添加访问静态ThreadLocal的静态方法(设值和取值);
(3)下面给出一个示例:
public class Counter { public static ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
//通过匿名内部类覆盖ThreadLocal的InitialValue方法,指定初值
protected Integer initialValue() {
return 0;
};
}; //封装业务处理,操作储存于ThreadLocal中的变量
public static Integer getNext(){
count.set(count.get()+1);
return count.get();
} public static Integer get(){
return count.get();
} public static void set(Integer value){
count.set(value);
}
}
public class ThreadLocalTest { public class TestThread extends Thread{ public void run() {
for(int i=0; i<10;i++){
System.out.println(Thread.currentThread()+" : "+Counter.getNext());
}
System.out.println("--------");
}
} public static void main(String[] args) throws InterruptedException {
ThreadLocalTest tt = new ThreadLocalTest(); Thread t1 = tt.new TestThread();
Thread t2 = tt.new TestThread();
Thread t3 = tt.new TestThread();
t1.start();
t2.start();
t3.start();
}
}
以上若有不当之前,欢迎拍砖。
最新文章
- sublime 安装笔记
- JQuery asp.net 简单入门
- mysql fetch 系列函数
- vijosP1437简单的口令
- C++学习(二)
- 一篇memcache基础教程
- shell的wc命令统计 head tail命令详解
- 沉默的螺旋--digest
- _spellmod_aura_on_classmask
- SQL Server用表组织数据
- 【Android】Bitmap加载图片错误 java.lang.OutOfMemoryError: bitmap size exceeds VM budget
- Java代码优化小结(一)
- svn安装时遇到问题总结
- [luogu3978][bzoj4001][TJOI2005]概率论【基尔霍夫矩阵+卡特兰数】
- Java中sort实现降序排序
- 【java高级编程】jdk自带事件模型编程接口
- Python学习笔记四:面向对象编程
- ni_set()函数的使用 以及 post_max_size,upload_max_filesize的修改方法
- ABAP-关于COMMIT WORK 和COMMIT WORK AND WAIT
- sqlserver年月日转汉字大写--自定义函数--繁体