JAVA多线程之ThreadLocal
来源:互联网 发布:2017网络新词 编辑:程序博客网 时间:2024/04/30 03:47
使用过单例模式的同学都知道,如果不做一些特殊处理,那么不管是谁通过getInstance()获取到的实例对象都是同一个的,如果某人获得实例对象后,修改一些属性值,那么所有人都会受到影响,不管是同线程内的同学,还是不同线程的同学,均会受到影响。例如下面例子。
package com.fei;/** * 每个线程代表一所学校,学校下面有年级 * */public class DataShare {public static void main(String[] args) throws InterruptedException {Thread qinghua=new Thread(new Runnable(){@Overridepublic void run() {School.getSchool().setName("清华大学");//修改学校名称new GradeOne().print();new GradeTwo().print();}});qinghua.setName("qinghua");qinghua.start();qinghua.join();Thread beijing =new Thread(new Runnable(){@Overridepublic void run() {//该学校发现School类中的学校名称和该校一样,故使用默认学校new GradeOne().print();new GradeTwo().print();}});beijing.setName("beijing");beijing.start();}}class School{private String name="北京大学";private static School instance=null;private School(){};public static School getSchool(){if(instance==null){synchronized(School.class){if(instance==null)instance=new School();}}return instance;}public String getName() {return name;}public void setName(String name) {this.name = name;}}class GradeOne{public void print(){System.out.println(Thread.currentThread().getName()+" :"+School.getSchool().getName()+"一年级");}}class GradeTwo{public void print(){System.out.println(Thread.currentThread().getName()+" :"+School.getSchool().getName()+"二年级");}}
运行结果
qinghua :清华大学一年级
qinghua :清华大学二年级
beijing :清华大学一年级
beijing :清华大学二年级
代码很简单,结果意料之中,因为清华大学和北京大学都使用了同一个School对象,所以清华大学修改学校名称时,北京大学也受到了影响。
现在的需求时,清华大学修改学校名称时,北京大学不受影响。也就是说每个学校都拥有自己的School对象,其他学校不能干扰,但是同一所学校内的所有年级使用School对象时却又是同一个的。那么我们可以把程序这样来改。
package com.fei;import java.util.HashMap;import java.util.Map;/** * 每个线程代表一所学校,学校下面有年级 * */public class DataShare {public static void main(String[] args) throws InterruptedException {Thread qinghua=new Thread(new Runnable(){@Overridepublic void run() {School.getSchool().setName("清华大学");//修改学校名称new GradeOne().print();new GradeTwo().print();}});qinghua.setName("qinghua");qinghua.start();qinghua.join();Thread beijing =new Thread(new Runnable(){@Overridepublic void run() {//该学校发现School类中的学校名称和该校一样,故使用默认学校new GradeOne().print();new GradeTwo().print();}});beijing.setName("beijing");beijing.start();}}class School{private String name="北京大学";private static School instance=null;//把每个线程对应的学校放到map中来private static Map<Thread,School> map=new HashMap<Thread,School>();private School(){};/** * 不需要使用synchronized了,因为就算多个线程同时进来,也是各取个的学校 */public static School getSchool(){instance = map.get(Thread.currentThread());if (instance == null) {instance = new School();map.put(Thread.currentThread(), instance);}return instance;}public String getName() {return name;}public void setName(String name) {this.name = name;}}class GradeOne{public void print(){System.out.println(Thread.currentThread().getName()+" :"+School.getSchool().getName()+"一年级");}}class GradeTwo{public void print(){System.out.println(Thread.currentThread().getName()+" :"+School.getSchool().getName()+"二年级");}}
运行结果:
qinghua :清华大学一年级
qinghua :清华大学二年级
beijing :北京大学一年级
beijing :北京大学二年级
我们实现需求了。
为了解决此类需求,在JDK1.5中,为我们提供了ThreadLocal这个类,我们可以将上面程序的School类做如下修改即可。为了节约篇幅,就只贴School类的源码了。
class School{private String name="北京大学";private static School instance=null;//把每个线程对应的学校放到map中来//private static Map<Thread,School> map=new HashMap<Thread,School>();private static ThreadLocal<School> threadLocal=new ThreadLocal<School>();private School(){};/** * 不需要使用synchronized了,因为就算多个线程同时进来,也是各取个的学校 */public static School getSchool(){//instance = map.get(Thread.currentThread());instance=threadLocal.get();if (instance == null) {instance = new School();//map.put(Thread.currentThread(), instance);threadLocal.set(instance);}return instance;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
上面的程序中我们用到了ThreadLocal类中的 set(T value)和get()方法,那么我们来看看他们的源码.
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//根据当前线程对象去取得当前线程中的ThreadLocalMap对象,是线程独自拥有的,不和其他线程公用 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
我们暂不去过分追究它的详细实现,我们从这个源码段中了解大意。表面的大意太简单明了了,也就不多说了,接下来,看看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; }
对于这方法,我们去看看initialValue()即可,其他的大意都很简单。
protected T initialValue() { return null; }
该方法返回null,也就是说初始值是null。
所以将上面的几个方法连起来看,就是get()如果ThreadLoal中还没T对象,则返回null。
接下来看看set(T value)
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
这代码在上面出现过了,大意也很明了。
- 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多线程之——ThreadLocal
- (8)Java多线程之ThreadLocal
- java多线程并发控制之ThreadLocal
- Java多线程学习之ThreadLocal源码分析
- java多线程之ThreadLocal源码分析
- 正则表达式判断手机号码属于哪个运营商
- ffmpeg与x264编码指南
- 一个人的旅行
- 百度权重是什么,有什么作用
- Code Fragment-对于一些状态性接口,应该有不同的阶段
- JAVA多线程之ThreadLocal
- Linux基本功十:bash运算符及启动脚本初步
- setjmp函数和longjmp函数
- Android 收集已发布程序的崩溃信息
- 全局变量,静态变量以及局部变量存放位置
- 若何做好微信营销的标题?
- Android 后台发送邮件 (收集应用异常信息+Demo代码)
- android蓝牙开发---与蓝牙模块进行通信
- 搜索引擎对IP的惩罚是否会影响整个服务器上的所有网站