浅谈 ThreadLocal

转载 2018年04月16日 10:55:14

https://www.jianshu.com/p/d635591b1967

有时,你希望将每个线程数据(如用户ID)与线程关联起来。尽管可以使用局部变量来完成此任务,但只能在本地变量存在时才这样做。也可以使用一个实例属性来保存这些数据,但是这样就必须处理线程同步问题。幸运的是,Java提供了java.lang.ThreadLocal类是一个简单(而且非常方便)的选择。

每个ThreadLocal实例都描述了一个线程局部变量,它是一个变量,它为每个访问变量的线程提供一个单独的存储槽(storage slot)。你可以将线程局部变量看作是一个多槽变量,其中每个线程可以在同一个变量中存储不同的值。每个线程只看到它的值,并且不知道其他线程在这个变量中有自己的值。

一般将ThreadLocal声明为ThreadLocal <T>,其中T标识存储在该变量中的值的类型。 这个类声明了下面的构造方法和方法:

  • ThreadLocal():创建一个新的线程局部变量。
  • T get():返回调用线程存储槽中的值。 如果线程调用此方法时不存在条目,则get()方法调用initialValue()方法。
  • T initialValue():创建调用线程的存储槽并在此槽中存储初始(默认)值。 初始值默认为null。 必须子类化ThreadLocal并重写此受保护的方法以提供更合适的初始值。
  • void remove():删除调用线程的存储槽。如果这个方法后面是get(),而没有插入set()方法,则get()调用initialValue()
    *void set(T value):将调用线程的存储槽的值设置为value

下面代码显示了如何使用ThreadLocal将不同的用户ID与两个线程相关联的示例。

package concurrency;

public class ThreadLocalDemo {
    private static volatile ThreadLocal<String> userID = new ThreadLocal<String>();

    public static void main(String[] args) {
        Runnable task = () -> {
            String name = Thread.currentThread().getName();
            if (name.equals("A")) {
                userID.set("yaya");
            } else {
                userID.set("maomao");
            }
            System.out.println(name + " " + userID.get());

        };

        Thread threadA = new Thread(task);
        threadA.setName("A");
        Thread threadB = new Thread(task);
        threadB.setName("B");

        threadA.start();
        threadB.start();
    } // end method main
} // end class ThreadLocalDemo

在实例化ThreadLocal并将引用分配给名为userID的volatile实例属性(该属性是volatile的,因为它是由不同的线程访问,这可能在多处理器/多核机器上执行——也可以指定为final),默认主线程创建两个线程在userID中存储不同的String对象并输出它们的值。

在Eclipse运行此程序,输出的结果为:

A yaya
B maomao

存储在线程局部变量中的值都互不相关的。 当一个新的线程被创建时,它会得到一个包含initialValue()值的新的存储槽。 也许你想从父线程(创建另一个线程的线程)传递值到子线程(创建的线程)。 则可以使用InheritableThreadLocal完成此任务。

InheritableThreadLocalThreadLocal的一个子类。 除了声明的InheritableThreadLocal()构造方法外,该类声明以下受保护的方法:

  • T childValue(T parentValue):在创建子线程时,计算这个可继承线程局部变量的子线程的初始值,将该值作为父线程值的一个函数。在启动子线程之前,从父线程内部调用此方法。该方法仅返回其输入变量,如果所需要的是其他行为,则应该重写此方法。

下面代码显示了如何使用InheritableThreadLocal将父线程的Integer对象传递给子线程。

public class InheritableThreadLocalDemo {
    private static final InheritableThreadLocal<Integer> intVal = new InheritableThreadLocal<Integer>();

    public static void main(String[] args) {
        Runnable rP = () -> {
            intVal.set(new Integer(10));
            Runnable rC = () -> {
                Thread thd = Thread.currentThread();
                String name = thd.getName();
                System.out.printf("%s %d%n", name, intVal.get());
            };
            Thread thdChild = new Thread(rC);
            thdChild.setName("Child");
            thdChild.start();
        };

        new Thread(rP).start();
    }
}

实例化InheritableThreadLocal并将其分配给final的实例属性(也可以使用volatile替代)intVal后,默认主线程创建一个父线程,该线程存储包含intVal中值的10的Integer对象。 父线程创建一个子线程,它访问intVal并检索其父线程的Integer对象。

执行此程序,其运行结果如下:

Child 10


多彩JavaScript教学视频

-
  • 1970年01月01日 08:00

浅谈Spring声明式事务管理ThreadLocal和JDKProxy

写这篇文章的目的,为了使大家更好的理解和摸清事务的规律,希望对新手学习事务这块内容时有所帮助。    在我们开发一个应用时,很多时候我们的一个业务操作会对数据库进行多次操作,有时候我们需要保证这...
  • sony315
  • sony315
  • 2011-09-10 23:50:37
  • 7496

ThreadLocal浅谈

ThreadLocal
  • aa1028181143
  • aa1028181143
  • 2016-03-14 13:57:15
  • 172

浅谈ThreadLocal

笔者在学习spring3中spring对事务管理的过程中,接触到了ThreadLocal的相关内容,比如在spring中,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchro...
  • xuexueenen
  • xuexueenen
  • 2014-02-08 00:34:44
  • 743

理解ThreadLocal

  • 2017年12月29日 10:55
  • 1.94MB
  • 下载

ThreadLocal的几种误区

  • 2008年10月17日 10:18
  • 26KB
  • 下载

由浅入深全面剖析ThreadLocal

前言这一阵子一直在看Picasso,在看的过程中发现了很多很有意思的东西,有的是以前见过甚至用过但是没有深入关注的,有些是以前根本没有见过的——比如今天要讲的ThreadLocal。(android ...
  • luoyanglizi
  • luoyanglizi
  • 2016-05-26 20:17:29
  • 9146

servlet 和 threadlocal 与 web容器

在传统的Web开发中,我们处理Http请求最常用的方式是通过实现Servlet对象来进行Http请求的响应。Servlet是J2EE的重要标准之一,规定了Java如何响应Http请求的规范。通过Htt...
  • ningguixin
  • ningguixin
  • 2013-12-03 10:48:42
  • 4191

利用ThreadLocal模式管理Session

利用ThreadLocal模式管理Session          在利用Hibernate开发DAO模块时,我们和Session打的交道最多,所以如何合理的管理Session,避免Sess...
  • Mr_HHH
  • Mr_HHH
  • 2016-02-17 16:22:19
  • 1531

ThreadLocal 与 static 变量 

 ThreadLocal是为解决多线程程序的并发问题而提出的,可以称之为线程局部变量。与一般的变量的区别在于,生命周期是在线程范围内的。static变量是的生命周期与类的使用周期相同,即只要类存在,那...
  • laorer
  • laorer
  • 2010-09-26 10:09:00
  • 7679
收藏助手
不良信息举报
您举报文章:浅谈 ThreadLocal
举报原因:
原因补充:

(最多只允许输入30个字)