ThreadLocal学习总结

ThreadLocal是一种比较规范的保持线程封闭性的方法。这个类能使线程中的某个值与保存值得对象关联起来。借助于get、set方法,为该线程拷贝了一份变量,方便后续该变量的复用。例如JDBC的Connection(单个Connection在多线程应用中且没有协同的情况下,不是线程安全的),通过将JDBC的连接保存到ThreadLocal中,没个线程都会拥有属于自己的连接。在任意线程A中,通过get()方法,可以获取属于A的connection。

private static ThreadLocal<Connection> connectionHolder=new ThreadLocal<Connection>(){

    @Override
    protected Connection initialValue() {
        return DriverManager.getConnection(DB_URL);
    }
  };public static Connection getConnection(){
    return connectionHolder.get();
}

摘自java doc:       This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via itsget orset method) has its own, independently initialized copy of the variable.ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).        ThreadLocal类为每个线程提供了局部变量。这些变量由各自的线程所拥有(通过get/set来访问),这些变量与线程的hashcode一一对应。已set()方法为例:

 /**
   * 根据currentThreadhashcode有关信息,在ThreadLocalMap中set其value

   * */public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }


该类提供的主要方法:

方法摘要
 Tget()
          返回此线程局部变量的当前线程副本中的值。(在get方法中可能会调用该方法)
protected  TinitialValue()
          返回此线程局部变量的当前线程的初始值。
 voidremove()
          移除此线程局部变量的值。
 voidset(T value)
          将此线程局部变量的当前线程副本中的值设置为指定值。

ThreadLocal的使用步骤一般为:

[1]  在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。

[2]  可以重写initValue()方法来方便get方法的初始化操作(如果不重写该方法,get返回为null,可以据此自定义get方法);

[3]  在线程中,使用get()/set()方法都会访问该对象,这样可以避免频繁使用的线程重复定义对象(开头的Connection例子)。 当某个频繁执行的操作需要一个临时对象,例如一个缓冲区,而同时又希望避免在每次执行时都重新分配该临时对象,就可以使用这项技术。

 

 参考博客:

[1]  http://lavasoft.blog.51cto.com/62575/51926/  (该文档作者似乎对ThreadLocal的作用理解的欠佳,但一些说明还是可以参考的) 
[2] http://www.java3z.com/cwbwebhome/article/article2/2952.html?id=1648[/url](两篇的例子雷同,不知道咋搞的,但是 这篇的总结可以参考下)

 

好吧,假使这个Student类似于DB Connection那样会频繁的使用,那么我就为每个线程(t1,t2....)创建一个Student副本,代码修改一下吧:(任意线程A第一次使用get,会调用initialValue构造一个年龄为0的Student作为副本哦,每次A再调用get,就会继续使用那个Student) 

public class test2 implements Runnable {

  /**
   * 根据currentThreadhashcode有关信息,在ThreadLocalMap中set其value
   * 
   * */

  // 创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
  private final static ThreadLocal<Student> studentLocal = new ThreadLocal<Student>() {

    @Override
    protected Student initialValue() {
      return new Student();
    }
  };

  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub

    test2 aTest = new test2();

    Thread t1 = new Thread(aTest, "a");
    Thread t2 = new Thread(aTest, "b");

    t1.start();
    t2.start();
  }

  @Override
  public void run() {
    accessStudent();
  }

  /**
   * 示例业务方法,用来测试
   */
  public void accessStudent() {
    // 获取当前线程的名字
    String currentThreadName = Thread.currentThread().getName();
    System.out.println(currentThreadName + " is running!");
    // 产生一个随机数并打印
    Random random = new Random();
    int age = random.nextInt(100);
    System.out.println("thread " + currentThreadName + " set age to:" + age);
    // 获取一个Student对象,并将随机数年龄插入到对象属性中
    Student aStudent = studentLocal.get();
    aStudent.setAge(age);
    studentLocal.set(aStudent);
    System.out.println("thread " + currentThreadName + " first read age is:"
        + studentLocal.get().getAge());
    try {
      Thread.sleep(500);
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    System.out.println("thread " + currentThreadName + " second read age is:"
        + studentLocal.get().getAge());
  }


}


 

 

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。 当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值