ThreadLocal实现线程范围的共享变量
1.ThreadLocal的作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,
多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另一
分数据。
2.每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加了一
条记录,key分别是各自的线程,value是各自的set方法进去的值,在线程结束时可以
调用ThreadLocal()方法,这样会更快释放内存,不调用也可以,因为线程结束后也
可以自动释放相关的ThreadLocal变量
3.ThreadLocal的应用场景
(1)例如struts2的ActionContext,同一段代码被不同的线程调用时,该代码操作的数据是
每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不
相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext
方法,拿到的都是同一个
(2) 银行转账包含一系列的操作,把转出账户的余额减少,把转入账户的余额增加,这两
个操作在同一个事务中进行,他们必须使用同一个数据库连接对象,而转入和转出分别
位于不同的账户对象的方法
直接用代码进行说明,创建三个线程,他们都访问了三个对象,第一个对象设置值,第二三个
对象取值,同一个线程设置的值,只能被相同的线程获取
public class ThreadScopeShareData {
private static int data =0 ;
private static Map<Thread,Integer> map = new HashMap<Thread,Integer> () ;
public static void main(String[]args) {
for (int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
pbulic void run() {
int data=new Random().nextInt();v
map.put(Thread.currentThread().getName(),data);
System.out.println(Thread.currentThread().getName() ++"put data" +data);
new A().get();
new B().get();
}
}).start();
}
}
staitc class A {
public void get() {
int data =map.get(Thread.currentThread().getName());
System.out.println("A from " +Thread.currentThread().getName() ++"put data" +data);
}
}
staitc class B{
public void get() {
int data =map.get(Thread.currentThread().getName());System.out.println("B from " +Thread.currentThread().getName() ++"put data" +data);
}
}
现在用jdk提供ThreadLocal实现上面的效果:
public class ThreadScopeShareData {
private static int data =0 ;
pivate static ThreadLocal<Integer> myThreadLocal = new ThreadLocal<Integer>();
public static void main(String[]args) {
for (int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
pbulic void run() {
int data=new Random().nextInt();v
myThreadLocal.set(data);
System.out.println(Thread.currentThread().getName() ++"put data" +data);
new A().get();
new B().get();
}
}).start();
}
}
staitc class A {
public void get() {
int data =myThreadLocal.get();
System.out.println("A from " +Thread.currentThread().getName() ++"put data" +data);
}
}
staitc class B{
public void get() {
int data =myThreadLocal.get();System.out.println("B from " +Thread.currentThread().getName() ++"put data" +data);
}
}
总结:myThreadLocal.set(data)存入与当前线程相关的数据,myThreadLocal.get()取出与当前线程相关的数据
义两个ThreadLocal对象,容易想到的是把n个变量定义成一个实体,把这个实体作为一个变量存入ThreadLocal中
,我取就能取到n个变量了,其实这是一种很烂的写法,我都懒得写,还是实现以下,看下面的代码:
public class ThreadScopeShareData {
private static int data =0 ;
private static ThreadLocal<MyThreadScopData>myThreadLocalDate = new ThreadLocal<MtyThreadScopData>() ;
public static void main(String[]args) {
for (int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
pbulic void run() {
int data=new Random().nextInt();vv
MyThreadScopData myData = new MyThreadScopData();
MyThreadScopData.SetAge(data);
MyThreadScopData.setName(data+"");
myThreadLocalDate.set(myData);
System.out.println(Thread.currentThread().getName() ++"put data" +data);
new A().get();
new B().get();
}
}).start();
}
}
staitc class A {
public void get() {
MtyThreadScopData = myThreadLocalDate.get();
System.out.println("A from " +Thread.currentThread().getName() ++"put data" +MtyThreadScopData.getName()+"--"+MtyThreadScopData.getAge());
}
}
staitc class B{
public void get() {
MtyThreadScopData = myThreadLocalDate.get();System.out.println("B from " +Thread.currentThread().getName() ++"put data" +MtyThreadScopData.getName()+"--"+MtyThreadScopData.getAge());
}
}
class myThreadScopData {
public int age ;
public Stirng nage ;
//set ,get 方法自己写
}
总结:我们用一个烂的方式实现把对象装进去,然后取出来,先让你认同用这种方式,下面我在用一个优雅
实现你就会认为我很牛
class myThreadScopData {
private MyThreadScopeData(){}
public staitc MyThreadScopeData getInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance =new MyThreadScopeData();
map.set(instance);
}
return instance;
}
private static ThreadLocal<MyThreadScopeData>map=new ThreadLocal<MyThreadScopeData>();
public int age ;
public Stirng nage ;
//set ,get 方法自己写
}
安全问题,两个线程没有共享一个实例,没必要考虑线程安全问题。