ThreadLocal的作用
从上一篇对于ThreadLocal的源码分析,可以看出ThreadLocal不是用来将解决共享对象的多线程访问问题,每个线程可以将线程的私有数据通过ThreadLocal的set方法设置到线程的私有的ThreadLocalMap中,其他线程无法访问到。各个线程中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocalMap中的数值都是不同对象
ThreadLocal的使用
首先定义一个全局共享的ThreadLocal
package com.ftf.thread.test;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadLocalPool {
public static final ThreadLocal<String> tl = new ThreadLocal<>();
public static void main(String[] args) {
LocalThread t1 = new LocalThread("线程A");
LocalThread t2 = new LocalThread("线程B");
LocalThread t3 = new LocalThread("线程C");
LocalThread t4 = new LocalThread("线程D");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class LocalThread extends Thread{
private static AtomicInteger at = new AtomicInteger();
public LocalThread(String name){
super(name);
}
@Override
public void run() {
for(int i = 0;i<3;i++){
ThreadLocalPool.tl.set(at.incrementAndGet()+"");
System.out.println(Thread.currentThread().getName()+" set value :" + ThreadLocalPool.tl.get());
}
}
}
输出结果:
线程A set value :1
线程D set value :4
线程C set value :3
线程B set value :2
线程C set value :7
线程D set value :6
线程A set value :5
线程D set value :10
线程C set value :9
线程B set value :8
线程B set value :12
线程A set value :11
从结果看出,每个线程都有自己的String,并且不会相互影响,用一个ThreadLocal也可以多次set一个数据,set仅仅表示的线程TheadLocal.ThreadLocalMap中table某一个位置value覆盖,而且对于同一个ThreadLocal对象而言,set后,table绝不会多出一个数据.
给ThreadLocal设置初始值,解决get返回null的问题
public static final ThreadLocal<String> tl = new ThreadLocal<String>(){
protected String initialValue() {
return "我是get时候为null时候的默认值";
};
};
对initialValue方法进行重写
InheritableThreadLocal实现父线程向子线程传递值
package com.ftf.thread.test;
import java.util.Date;
public class InheritableTest extends InheritableThreadLocal<String> {
@Override
protected String initialValue() {
return new Date().getTime()+"";
}
/*@Override
protected String childValue(String parentValue) {
return "子线程加上的值";
}*/
public static void main(String[] args) throws InterruptedException {
Tools.it.set("我是父线程定义的值");
for(int i=0;i<3;i++){
System.out.println("Main线程中值:"+Tools.it.get());
Thread.sleep(1000);
}
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程中获取到的值"+Tools.it.get());
}
});
t.start();
}
}
class Tools {
public static final InheritableTest it = new InheritableTest();
}
输出结果
Main线程中值:我是父线程定义的值
Main线程中值:我是父线程定义的值
Main线程中值:我是父线程定义的值
子线程中获取到的值我是父线程定义的值
main线程是父线程,里面启动子线程Thread,从结果看出,子线程获取到的值从父线程而来,而不是初始值
* 将上面的ChildValue方法放开,就能定义再次修改继承过来的值
Main线程中值:我是父线程定义的值
Main线程中值:我是父线程定义的值
Main线程中值:我是父线程定义的值
子线程中获取到的值子线程加上的值
ThreadLocal再总结
1. TheadLocal可以看做是一个抽屉,每个线程都能向里面放数据,取数据,不会相互干扰
2. 同步和ThreadLocal是解决多线程中数据访问问题的两种思路,前者是数据共享,后者是数据隔离
3. 同步是一种时间换空间的思想,ThreadLocal是一种空间换时间的思想
4. ThreadLocal既然与线程相关,对于java web而言,ThreadLocal设置的是只在一次请求中有效,是不是和request很像?因为request里面的内容只是在一次请求中有效,对比一下两者的区别:
* ThreadLocal只能去设置一个值,因为每次set值的时候,会找到threadLocal相同的entry,进行覆盖
,而request每次可以设置多个值,是因为key-value的结构
参考博客:
http://www.cnblogs.com/xrq730/p/4854820.html
《Java多线程核心技术》