有时,你希望将每个线程数据(如用户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

浅谈 ThreadLocal的更多相关文章

  1. 浅谈ThreadLocal模式

    一.前言: ThreadLocal模式,严格意义上不是一种设计模式,而是java中解决多线程数据共享问题的一个方案.ThreadLocal类是java JDK中提供的一个类,用来解决线程安全问题,并不 ...

  2. 浅谈Java线程安全

    浅谈Java线程安全 - - 2019-04-25    17:37:28 线程安全 Java中的线程安全 按照线程安全的安全程序由强至弱来排序,我们可以将Java语言中各种操作共享的数据分为以下五类 ...

  3. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  4. 浅谈flask源码之请求过程

    更新时间:2018年07月26日 09:51:36   作者:Dear.   我要评论   这篇文章主要介绍了浅谈flask源码之请求过程,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随 ...

  5. Spring5.0源码学习系列之浅谈BeanFactory创建

    Spring5.0源码学习系列之浅谈BeanFactory创建过程 系列文章目录 提示:Spring源码学习专栏链接 @ 目录 系列文章目录 博客前言介绍 一.获取BeanFactory主流程 二.r ...

  6. Spring5.0源码学习系列之浅谈循环依赖问题

    前言介绍 附录:Spring源码学习专栏 在上一章的学习中,我们对Bean的创建有了一个粗略的了解,接着本文浅谈Spring循环依赖问题,这是一个面试比较常见的问题 1.什么是循环依赖? 所谓的循环依 ...

  7. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  8. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  9. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

随机推荐

  1. 【linux之链接,函数,随机数】

    一.链接 硬链接(hard link):同一个文件使用了多个别名.新建文件是已经存在的一个别名,,当原文件删除时,新建的文件仍然可以使用.硬链接和原来的文件没有什么区别,而且共享一个inode号.通过 ...

  2. c#抽取pdf文档标题——前言

    由于工作的需要,研究c#抽取pdf文档标题有3个月了.这项工作是一项"伟大而艰巨"的任务.应该是我目前研究工作中最长的一次.我觉得在长时间忙碌后,应该找些时间,把自己的心路历程归纳 ...

  3. Eclipse Web项目配置

    1.每次重开workspace都要重新配置一次 2.new web project之前配置 3.Windows-Preferences-(所有都要记得Apply) General   Maven P. ...

  4. WebService下实现大数据量的传输

    设置RemotingFormat = SerializationFormat.Binary;再序列化,通过WebService传输,客户端接收,再反序列化,确实效果大大的优于直接传送DataSet,不 ...

  5. javascript 原型及原型链详解

    我们创建的每个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个原型对象,而这个原型对象中拥有的属性和方法可以被所以实例共享. function Person(){ } Pe ...

  6. 解决iar试调时程序无法进入主函数的问题

    尼玛,我TM当时核心板上还接着摄像头,啊啊啊啊,必须吧摄像头关了,不然,k60初始化时会检测io口状态,状态不正确当然无法进入主函.摄像头上电即输出数据,会对单片机上电检测造成干扰.

  7. 纯代码实现wordpress文章隐藏内容评论可见

    在很多网站上都看过这个效果,比如说知己知彼网站,他的部分资源是需要我们评论后才能下载的,那么这个到底有什么用呢,对我而言,除了拿来装逼,还可以增加我的评论数量,不多说,先看看效果: 其实WordPre ...

  8. python解决图的最短路径问题

    在hihoCoder上遇到一个算法题目,描述如下: 对图结构有了解的不难发现,这是经典的求图的最短路径问题.以下是python代码: def findMin(row): minL = max(row) ...

  9. 使用openssl演练数字签名

    以下代码摘自网上,设置一个server和client,client代码如下: package main import (    "fmt"    "io/ioutil&q ...

  10. 格式化JSON数据

    function formatJson(json, options) { var reg = null, formatted = '', pad = 0, PADDING = ' '; options ...