知识大全 Java并发编程实践之ThreadLocal变量

Posted 变量

篇首语:犀渠玉剑良家子,白马金羁侠少年。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java并发编程实践之ThreadLocal变量相关的知识,希望对你有一定的参考价值。

Java并发编程实践之ThreadLocal变量  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  早在JDK 的版本中就提供了java lang ThreadLocal 为解决多线程程序的并发问题提供了一种新的思路 使用这个工具类可以很简洁地编写出优美的多线程程序

  ThreadLocal很容易让人望文生义 想当然地认为是一个 本地线程 其实 ThreadLocal并不是一个Thread 而是Thread的局部变量 也许把它命名为ThreadLocalVariable更容易让人理解一些 当使用ThreadLocal维护变量时 Threadlocal为每个使用该变量的线程提供独立的变量副本 所以每一个线程都可以独立地改变自己的副本 而不会影响其他线程所独立的副本

  从线程的角度看 目标变量就是线程的本地变量 这也是类名中 Local 所要表达的意思 线程局部变量并不是Java的新发明 很多语言(如IBM XL FORTRAN)在语法层面就提供了线程局部变量 在Java中没有提供语言级支持 而是变相地通过ThreadLocal的类提供支持

  JDK 以后提供了泛型支持 ThreadLocal被定义为支持泛型

  public class ThreadLocal<T> extends Object

  T为线程局部变量的类型 该类定义了 个方法

   ) protected T initialValue() 返回此线程局部变量的当前线程的 初始值 线程的第一次使用get()方法访问变量时将调用此方法 但如果线程之前调用了set(T)方法 则不会对该线程再调用initialValue方法 通常 此方法对每个线程最多调用一次 但如果在调用get()后又调用了remove() 则可能再次调用此方法

  该实现返回null 如果程序员希望线程局部变量具有null以外的值 则必须为ThreadLocal创建子类 并重写此方法 通常将使用匿名内部类完成此操作

   )public Tget() 返回此线程局部变量的当前线程副本中的值 如果变量没有用于当前线程的值 则先将其初始化为调用initialValue方法返回的值

   )public void Set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值 大部分子类不需要重写此方法 它们只依靠initialValue()方法来设置线程局部变量的值

   )public void remove() 移除此线程局部变量当前线程的值 如果此线程局部变量随后被当前线程读取 且这期间当前线程没有设置其值 则将调用其initialValue()方法重新初始化其值 这将导致在当前线程多次调用initialValue方法

  下面是一个使用ThreadLocal的例子 每个线程产生自己独立的序列号 就是使用Threadlocal存储每个线程独立的版本号副本 线程之间互不干扰

  public class SequenceNumber

  //定义匿名内部类创建ThreadLocal的变量

  private static ThreadLocal<Integer> seqNum=new ThreadLocal<Integer>()

  //覆蓋初始化方法

  public Integer initialValue()

  return ;

  

  ;

  //下一个序列号

  public int getNextNum()

  seqNum set(seqNum get()+ )

  return seqNum get()

  

  private static class TestClient extends Thread

  private SequenceNumber sn;

  public TestClient(SequenceNumber sn)

  this sn=sn;

  

  //产生序列号

  public void run()

  for(int i= ;i< ;i++)

  System out println( Thread[ +Thread currentThread() getName()+

   ] sn[ +sn getNextNum()+ ] )

  

  

  

  public static void main(String[] args)

  SequenceNumber seqNum=new SequenceNumber()

  //三个线程产生各自的序列号

  TestClient t =new TestClient(seqNum)

  TestClient t =new TestClient(seqNum)

  TestClient t =new TestClient(seqNum)

  t start()

  t start()

  t start()

  

  

  public class SequenceNumber //定义匿名内部类创建ThreadLocal的变量 private static ThreadLocal<Integer> seqNum=new ThreadLocal<Integer>() //覆蓋初始化方法 public Integer initialValue() return ; ; //下一个序列号 public int getNextNum() seqNum set(seqNum get()+ ) return seqNum get() private static class TestClient extends Thread private SequenceNumber sn; public TestClient(SequenceNumber sn) this sn=sn; //产生序列号 public void run() for(int i= ;i< ;i++) System out println( Thread[ +Thread currentThread() getName()+ ] sn[ +sn getNextNum()+ ] ) public static void main(String[] args) SequenceNumber seqNum=new SequenceNumber() //三个线程产生各自的序列号 TestClient t =new TestClient(seqNum) TestClient t =new TestClient(seqNum) TestClient t =new TestClient(seqNum) t start() t start() t start()

  程序的运行结果如下

  Java代码

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ]

  Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ] Thread[Thread ] sn[ ]

  从运行结果可以看出 使用了ThreadLocal后 每个线程产生了独立的序列号 没有相互干扰 通常我们通过匿名内部类的方式定义ThreadLocal的子类 提供初始的变量值

  ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题

  在同步机制中 通过对象的锁机制保证同一时间只有一个线程访问变量 这时该变量是多个线程共享的 使用同步机制要求程序缜密地分析什么时候对变量进行读写 什么时候需要锁定某个对象 时候时候释放对象锁等繁杂的问题 程序设计和编写难度相对较大

  而ThreadLocal则从另一个角度来解决多线程的并发访问 ThreadLocal会为每一个线程提供一个独立的变量副本 从而隔离了多个线程对数据的访问冲突 因为每一个线程都拥有自己的变量副本 从而也就没有必要对该变量进行同步了 ThreadLocal提供了线程安全的共享对象 在编写多线程代码时 可以把不安全的变量封装进ThreadLocal

  概况起来说 对于多线程资源共享的问题 同步机制采用了 以时间换空间 的方式 而ThreadLocal采用了 以空间换时间 的方式 前者仅提供了一份变量 让不同的线程排队访问 而后者为每一个线程都提供了一份变量 因此可以同时访问而互不影响

  需要注意的是ThreadLocal对象是一个本质上存在风险的工具 应该在完全理解将要使用的线程模型之后 再去使用ThreadLocal对象 这就引出了线程池(thread pool)的问题 线程池是一种线程重用技术 有了线程池就不必为每个任务创建线的线程 一个线程可能会多次使用 用于这种环境的任何ThreadLocal对象包含的都是最后使用该线程的代码锁设置的状态 而不是在开始执行新线程时所具有的未被初始化的状态

cha138/Article/program/Java/hx/201311/26985

相关参考

知识大全 Java 理论与实践: 正确使用 volatile 变量 线程同步

Java理论与实践:正确使用volatile变量线程同步  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下

知识大全 Java进行并发多连接socket编程

Java进行并发多连接socket编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java多

知识大全 Java多线程开发之线程局部变量的使用

Java多线程开发之线程局部变量的使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &

知识大全 深入ThreadLocal

Java线程:深入ThreadLocal  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Thre

知识大全 Java泛型编程之诀窍

Java泛型编程之诀窍  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &nb

知识大全 Java编程思想之静态技术

Java编程思想之静态技术  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  静态技术包括静态数据静

知识大全 Java高级编程之displayTag学习摘要

Java高级编程之displayTag学习摘要  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  t

知识大全 Java多线程编程基础之线程对象

Java多线程编程基础之线程对象  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &nbs

知识大全 JAVA编程解析之classpath的深入理解

JAVA编程解析之classpath的深入理解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  现

知识大全 实战Java多线程编程精要之高级支持

实战Java多线程编程精要之高级支持  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  线程组  线