06_张孝祥_多线程_ThreadLocal类及应用技巧

来源:互联网 发布:无印良品文具淘宝 编辑:程序博客网 时间:2024/05/19 17:04

设计

ThreadLocal并不是包含Map对象,而是这些特定于线程的值保存在Thread对象中,java.lang.Thread定义了变量:ThreadLocal.ThreadLocalMap threadLocals = null,当线程终止后,这些值会作为垃圾回收。

ThreadLocal.ThreadLocalMap中定义Entry[] table变量,Entry类定义为Entry(ThreadLocal k, Object v),因此是线程java.lang.Thread包含了所有的ThreadLocal及该ThreadLocal中该线程对应的值。

ThreadLocal.set()创建新的Entry对象,并保存到ThreadLocal.ThreadLocalMap变量Entry[] table
ThreadLocal.get()时,各线程从自己的ThreadLocalMap对象变量Entry[] table中取出与该ThreadLocal对应的Entry对象,并取出entry保存的值。

使用

JDK1.5提供了ThreadLocal类来方便实现线程范围内的数据共享,它的作用就相当于 05_张孝祥Java多线程线程范围内共享变量的概念与作用 中的Map(内部并不是Map),也就是让每个线程拥有自己的值

一个ThreadLocal对象只能记录一个线程内部的一个共享变量,需要记录多个共享数据,可以创建多个ThreadLocal对象,或者将这些数据进行封装,将封装后的数据对象存入ThreadLocal对象中。

线程结束后也可以自动释放相关的ThreadLocal变量,也可以调用ThreadLocal.remove()方法用来更快释放内存。

代码

下面用ThreadLocal类实现,替代 05_张孝祥Java多线程线程范围内共享变量的概念与作用 实现

import java.util.Random;  public class ThreadLocalTest {      private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();      public static void main(String[] args) {          //启动两个线程          for (int i = 0; i < 2; i++) {              new Thread(new Runnable() {                  @Override                  public void run() {                      //创建每个线程私有的变量                      int data = new Random().nextInt(100);                      System.out.println(Thread.currentThread().getName()+" has put data: "+data);                      //往local里面设置值                      threadLocal.set(data);                      new A().get();                      new B().get();                  }              }).start();          }      }      static class A{          public void get(){              int data =threadLocal.get();              System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);          }      }    static class B{          public void get(){              int data =threadLocal.get();              System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);          }      }  }  

假设需要保存不止一个值,可以把其他属性的值打包成一个类,然后将该类设置成ThreadLocal的值。

下面代码中,在类MyThreadLocalScopeDate里面定义了一个静态变量Map,用来保存所有线程创建的MyThreadLocalScopeDate,并使用单例使得不管多少线程都只创建一个MyThreadLocalScopeDate对象。

import java.util.Random;  public class ThreadLocalTest {      private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();      public static void main(String[] args) {          //启动两个线程          for (int i = 0; i < 2; i++) {              new Thread(new Runnable() {                  @Override                  public void run() {                      //创建每个线程私有的变量                      int data = new Random().nextInt(100);                      System.out.println(Thread.currentThread().getName()+" has put data: "+data);                      //往local里面设置值                      threadLocal.set(data);                      //获取自己线程的MyThreadLocalScopeDate实例对象                      MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();                      myData.setName("name"+data);                      myData.setAge(data);                      new A().get();                      new B().get();                  }              }).start();          }      }      static class A{          public void get(){              int data =threadLocal.get();              System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);              MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();              System.out.println("A from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());          }      }      static class B{          public void get(){              int data =threadLocal.get();              System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);              MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();              System.out.println("B from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());          }      }  }  class MyThreadLocalScopeDate{//单例模式      private MyThreadLocalScopeDate(){};//构造方法私有化      private static ThreadLocal<MyThreadLocalScopeDate> map = new ThreadLocal<MyThreadLocalScopeDate>();//封装MyThreadLocalScopeDate是线程实现范围内共享      //思考AB两个线程过来的情况 自己分析 AB都需要的自己的对象 没有关系 所以不需要同步 如果有关系就需要同步了      public static /*synchronized*/MyThreadLocalScopeDate getThreadInstance(){          MyThreadLocalScopeDate instance =map.get();          if(instance==null){              instance = new MyThreadLocalScopeDate();              map.set(instance);          }          return instance;      }      private String name;      private int age;      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;      }  }

参考

06.ThreadLocal类及应用技巧
正确理解ThreadLocal
多线程06_张孝祥-ThreadLocal类及应用技巧

原创粉丝点击