`
lansim
  • 浏览: 3399 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

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同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

分享到:
评论

相关推荐

    java线程详解

    八、线程同步小结 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:volatile关键字 Java线程:新特征-线程池 一、固定大小的线程池 二、单任务线程池 三、可变尺寸的线程池 四、延迟连接池 五、...

    疯狂JAVA讲义

    学生提问:老师,我想学习Java编程,到底是学习Eclipse好呢,还是学习JBuilder好呢? 21 1.9 本章小结 22 本章练习 22 第2章 理解面向对象 23 2.1 面向对象 24 2.1.1 结构化程序设计简介 24 2.1.2 程序的三种...

    Java线程安全问题小结_动力节点Java学院整理

    Java内存模型(JMM)是Java语言为了保证跨平台的并发正确性而设定的一套规范,它规定了线程如何访问和修改内存中的数据。 1. 可见性:Java内存模型确保了当一个线程修改了共享变量后,其他线程能看到这个修改。线程...

    Spring.3.x企业应用开发实战(完整版).part2

    1.8 小结 第2章 快速入门 2.1 实例功能概述 2.1.1 比Hello World更适用的实例 2.1.2 实例功能简介 2.2 环境准备 2.2.1 创建库表 2.2.2 建立工程 2.2.3 类包及Spring配置文件规划 2.3 持久层 2.3.1 建立领域对象 ...

    Spring3.x企业应用开发实战(完整版) part1

    1.8 小结 第2章 快速入门 2.1 实例功能概述 2.1.1 比Hello World更适用的实例 2.1.2 实例功能简介 2.2 环境准备 2.2.1 创建库表 2.2.2 建立工程 2.2.3 类包及Spring配置文件规划 2.3 持久层 2.3.1 建立领域对象 ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.6.2.1. 文档视图定义 14.6.2.2. Controller 代码 14.6.2.3. Excel视图子类 14.6.2.4. PDF视图子类 14.7. JasperReports 14.7.1. 依赖...

    Spring中文帮助文档

    14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.7. JasperReports 14.7.1. 依赖的资源 14.7.2. 配置 14.7.3. 构造ModelAndView 14.7.4. 使用子报表 14.7.5. 配置Exporter的...

    Spring 2.0 开发参考手册

    14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.7. JasperReports 14.7.1. 依赖的资源 14.7.2. 配置 14.7.3. 构造ModelAndView 14.7.4. 使用子报表 14.7.5. 配置Exporter的...

    Spring API

    14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.7. JasperReports 14.7.1. 依赖的资源 14.7.2. 配置 14.7.3. 构造ModelAndView 14.7.4. 使用子报表 14.7.5. 配置Exporter的...

    spring chm文档

    14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.7. JasperReports 14.7.1. 依赖的资源 14.7.2. 配置 14.7.3. 构造ModelAndView 14.7.4. 使用子报表 14.7.5. 配置Exporter的...

Global site tag (gtag.js) - Google Analytics