ThreadLocal实现线程范围的共享变量

来源:互联网 发布:淘宝卖品牌要授权吗 编辑:程序博客网 时间:2024/05/16 02:24

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代表一个变量,故其中只能放入一个数据,你有两个变量都要线程范围内数据共享则要定

义两个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 方法自己写


}


总结:用了类似单例模式的懒汉模式,调用getInstance()不存在线程

安全问题,两个线程没有共享一个实例,没必要考虑线程安全问题。













 

0 0
原创粉丝点击