Java中的ThreadLocal的学习小结


最近看了Spring和Hibernate的源码,发现大量使用了ThreadLocal,于是上网学习了一些关于ThreadLocal的文章,将自己的学习小结贴上来,大家一起进步!

 

1.ThreadLocal用来解决多线程程序的并发问题


2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护

变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都

可以独立地改变自己的副本,而不会影响其它线程所对应的副本.


3.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要

表达的意思。


4.线程局部变量并不是Java的新发明,Java没有提供在语言级支持(语法上),而是变

相地通过ThreadLocal的类提供支持.


5.ThreadLocal类中的方法:(JDK5版本之后支持泛型)

    void set(T value)

          将此线程局部变量的当前线程副本中的值设置为指定值

    void remove()

          移除此线程局部变量当前线程的值

    protected T initialValue()

          返回此线程局部变量的当前线程的“初始值”

    T get()

          返回此线程局部变量的当前线程副本中的值


6.ThreadLocal的原理:

   ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很

简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素

的键为线程对象,而值对应线程的变量副本


7.自己模拟ThreadLocal:

    public class SimpleThreadLocal{

       private Map valueMap=Collections.synchronizedMap(new HashMap());

       public void set(Object newValue){

          valueMap.put(Thread.currentThread(),newValue);//键为线程对象,值


为本线程的变量副本

       }

       public Object get(){

          Thread currentThread=Thread.currentThread();

          Object o=valueMap.get(currentThread);//返回本线程对应的变量

          if(o==null&&!valueMap.containsKey(currentThread)){

              //如果在Map中不存在,放到Map中保存起来

              o=initialValue();

              valueMap.put(currentThread,o);

          }

          return o;

       }

       public void remove(){

           valueMap.remove(Thread.currentThread());

       }

       public void initialValue(){

           return null;

       }

    }



8.使用ThreadLocal的具体例子:

   public class SequenceNumber{

      //通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值

      private static ThreadLocal<Integer> seNum=new ThreadLocal<Integer>


(){

       protected Integer initialValue(){

           return 0;

        }

      }


      public Integer getNextNum(){

           seNum.set(seNum.get()+1);

           return seNum.get();

      }


      public static void main(String[] args){

       SequenceNumber sn=new SequenceNumber();

        //3个线程共享sn,各自产生序列号

        TestClient t1 = new TestClient(sn);

TestClient t2 = new TestClient(sn);

TestClient t3 = new TestClient(sn);

t1.start();

t2.start();

t3.start();    

      }


      private static class TestClient extends Thread{

          private SequenceNumber sn;

          public TestClient(SequenceNumber sn){

              this.sn=sn;

          }

          public void run(){

              //每个线程打印3个序列号

              for(int i=0;i<3;i++){

                  System.out.println("thread["+Thread.currentThread


().getName()+",sn["+sn.getNextNum()+"]");

              }

          }

      }.

   }


   解析:通常我们通过匿名内部类的方式定义ThreadLocal的子类,提供初始的变量

值.

        考察输出的结果信息(将上段代码在IDE运行),我们发现每个线程所产生的序号虽然都共享同一个

SequenceNumber实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序

列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。


9.ThreadLocal和同步机制的比较:

    相同点:ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲

突问题

    区别:在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。

这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量

进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序

设计和编写难度相对较大。

      ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每

一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为

每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。

ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变

量封装进ThreadLocal.


    概括来说:对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方

式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同

的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互

不影响。

 

总结:ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变

量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题

更简单,更方便,且结果程序拥有更高的并发性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值