线程范围内共享变量的概念与作用
1.作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。
2.每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。
3.ThreadLocal的应用场景:
(1)订单处理包含一系列操作:减少库存量,增加一条流水台账,修改总账,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面的操作回滚,否则,提交所有的操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。
(2)例如Strut2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。
(3)实例案例:定义一个全局共享的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着看各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共享同一份数据。
重点:(4)实现对ThreadLocal变量的封装,让外界不要直接操作ThreaLocal变量。
对基本类型的数据的封装,这种应用相对很少见。
对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。
实例1:自定义一个map实现ThreadLocal实现线程间数据独立,在使用ThreadLocal来实现,加深对ThreadLocal原理大的理解
public class ThreadScopeShareData {
// private static int data=0;
/* private static Map<Thread,Integer> map = new HashMap<Thread,Integer>();*/
private static ThreadLocal<Integer> map = new ThreadLocal<Integer>();
public static void main(String[] args){
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"has put data"+data);
/* map.put(Thread.currentThread(), data);*/
map.set(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
/* public void get(){
System.out.println("A from"+Thread.currentThread().getName()+"get data"+map.get(Thread.currentThread()));
}*/
public void get(){
System.out.println("A from "+Thread.currentThread().getName()+" get data "+map.get());
}
}
static class B{
/* public void get(){
System.out.println("B from"+Thread.currentThread().getName()+"get data"+map.get(Thread.currentThread()));
}*/
public void get(){
System.out.println("B from "+Thread.currentThread().getName()+" get data "+map.get());
}
}
}
实例2:当数据较多时,将多个数据惊醒封装,使用引用类型数据
public class ThreadLocalText {
/* private static ThreadLocal<Integer> map = new ThreadLocal<Integer>();*/
public static void main(String[] args){
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+" has put data "+data);
/* map.put(Thread.currentThread(), data);*/
/*map.set(data);*/
MyThreadLocal.getInstance().setName("name"+data);
MyThreadLocal.getInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
/* public void get(){
System.out.println("A from"+Thread.currentThread().getName()+"get data"+map.get(Thread.currentThread()));
}*/
public void get(){
/*System.out.println("A from "+Thread.currentThread().getName()+" get data "+map.get());*/
MyThreadLocal mydata = MyThreadLocal.getInstance();
System.out.println("A from "+Thread.currentThread().getName()+mydata.getName()+" get data "+mydata.getAge());
}
}
static class B{
/* public void get(){
System.out.println("B from"+Thread.currentThread().getName()+"get data"+map.get(Thread.currentThread()));
}*/
public void get(){
/*System.out.println("B from "+Thread.currentThread().getName()+" get data "+map.get());*/
MyThreadLocal mydata = MyThreadLocal.getInstance();
System.out.println("B from "+Thread.currentThread().getName()+mydata.getName()+" get data "+mydata.getAge());
}
}
static class MyThreadLocal{
private String name;
private int age;
private MyThreadLocal(){}
public static MyThreadLocal getInstance(){
MyThreadLocal instance =map.get();
if(instance==null){
instance = new MyThreadLocal();
map.set(instance);
}
return instance;
}
private static ThreadLocal<MyThreadLocal> map = new ThreadLocal<MyThreadLocal>();
/*private MyThreadLocal instance = null;*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}