ThraedLocal

来源:互联网 发布:ubuntu 配置ssh服务器 编辑:程序博客网 时间:2024/06/07 17:08

Java:ThreadLocal究竟有什么用呢?

说是用了ThreadLocal,那么每个变量就都有自己的副本了,那直接在线程里声明自己的私有变量不就行了吗?为什么还要使用ThreadLocal呢?
从如下8点来讲解一下: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不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点:
1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行
的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。

ThreadLocal的应用场合,我觉得最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。

小结

  ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。



推荐阅读:ThreadLocal 那点事儿https://my.oschina.net/huangyong/blog/159489
https://my.oschina.net/huangyong/blog/159725
彻底理解ThreadLocal http://blog.csdn.net/lufeng20/article/details/24314381/

0 0
原创粉丝点击