ThreadLocal小记
API:
-
public class ThreadLocal<T>
- extends
Object - extends
该类提供了线程局部 (thread-local) 变量。
这些变量不同于它们的普通相应物。由于訪问某个变量(通过其 get 或 set 方法)的每一个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例一般是类中的 private static 字段,它们希望将状态与某一个线程(比如,用户 ID 或事务 ID)相关联。
每一个线程都保持对其线程局部变量副本的隐式引用,仅仅要线程是活动的而且 ThreadLocal 实例是可訪问的。在线程消失之后。其线程局部实例的全部副本都会被垃圾回收(除非存在对这些副本的其它引用)。
Method:
initialValue
protected T initialValue()
- 返回此线程局部变量的当前线程的“初始值”。
线程第一次使用
get()
方法訪问变量时将调用此方法,但假设线程之前调用了
方法。则不会对该线程再调用 initialValue 方法。
set(T)通常,此方法对每一个线程最多调用一次。但假设在调用
get()
后又调用了
remove()
,则可能再次调用此方法。该实现返回 null;假设程序猿希望线程局部变量具有 null 以外的值。则必须为 ThreadLocal 创建子类。并重写此方法。通常将使用匿名内部类完毕此操作。
-
- 返回:
- 返回此线程局部变量的初始值
get
public T get()
- 返回此线程局部变量的当前线程副本中的值。假设变量没实用于当前线程的值,则先将其初始化为调用
initialValue()
方法返回的值。 -
- 返回:
- 此线程局部变量的当前线程的值
set
public void set(T value)
- 将此线程局部变量的当前线程副本中的值设置为指定值。大部分子类不须要重写此方法,它们仅仅依靠
initialValue()
方法来设置线程局部变量的值。 -
- 參数:
value
- 存储在此线程局部变量的当前线程副本中的值。
remove
public void remove()
移除此线程局部变量当前线程的值。
假设此线程局部变量随后被当前线程 读取,且这期间当前线程没有 设置其值。则将调用其 initialValue()
方法又一次初始化其值。
这将导致在当前线程多次调用
initialValue 方法。
例1:
package com.example; import java.util.Date;
import java.util.concurrent.TimeUnit; public class SafeTask implements Runnable{
private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() {
protected Date initialValue(){
return new Date();
}
}; @Override
public void run() { System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());
try {
TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get()); } public static void main(String[] args) {
SafeTask task=new SafeTask();
for (int i=0; i<3; i++){
Thread thread=new Thread(task);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
执行结果:
Starting Thread: 15 : Mon Nov 17 13:36:33 CST 2014
Starting Thread: 17 : Mon Nov 17 13:36:35 CST 2014
Thread Finished: 17 : Mon Nov 17 13:36:35 CST 2014
Starting Thread: 18 : Mon Nov 17 13:36:37 CST 2014
Thread Finished: 15 : Mon Nov 17 13:36:33 CST 2014
Thread Finished: 18 : Mon Nov 17 13:36:37 CST 2014
从结果,能够看到,三个线程各自存储和訪问各自维护的startDate局部变量。
解析:
ThreadLocal有一个内部静态类ThreadLocalMap来管理线程中的变量。能够简单的将其理解成一个Map。
而Map中存放的指的方式是:用当前的线程来做为KEY。线程相应的变量值作为VALUE。
当某一线程要获取当前变量的值时,就使用ThreadLocal.get()方法。通过线程自身作为KEY,去ThreadLocalMap中查找相应的值。
这样就能够解释“每一个线程都保持对其线程局部变量副本的隐式引用”。
而为了使每一个线程都能够使用该变量的副本使用,“ThreadLocal 实例一般是类中的 private static 字段”。
为了更好的理解ThreadLocal这样的机制,请看以下的样例。
例2:
package com.example; import java.util.Date;
import java.util.concurrent.TimeUnit; public class SafeTask implements Runnable{ private static ThreadLocal<Date> startDate = new ThreadLocal<Date>(); @Override
public void run() {
startDate = new ThreadLocal<Date>();
startDate.set(new Date());
System.out.printf("Thread: %s new startDate.\n", Thread.currentThread().getId());
System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());
try {
TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get()); } public static void main(String[] args) {
SafeTask task=new SafeTask();
for (int i=0; i<3; i++){
Thread thread=new Thread(task);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
运行结果:
Thread: 15 new startDate.
Starting Thread: 15 : Mon Nov 17 13:55:16 CST 2014
Thread: 17 new startDate.
Starting Thread: 17 : Mon Nov 17 13:55:18 CST 2014
Thread Finished: 15 : null
Thread Finished: 17 : Mon Nov 17 13:55:18 CST 2014
Thread: 18 new startDate.
Starting Thread: 18 : Mon Nov 17 13:55:20 CST 2014
Thread Finished: 18 : Mon Nov 17 13:55:20 CST 2014
为什么例2的结果中会出现null呢?
原因就在于,代码在线程中又一次创建来ThreadLocal
startDate = new ThreadLocal<Date>();
这样做,就导致了startDate指向了新的ThreadLocal对象。那么之前存放在当中的副本就丢失了,所以才会出现null的情况。
通过以上的样例,我们就能理解为什么ThreadLocal 实例一般是类中的 private static 字段。
我们须要明确。每一个线程中变量的副本,是通过线程的KEY和变量的VALUE存放在ThreadLocalMap中,而不是说。为每一个线程建立ThreadLocal。
就类而言,他实际仅仅维护和管理着一个ThreadLocal。
PS:代码部分截取来自《Java 7 Concurrency Cookbook》
ThreadLocal小记的更多相关文章
- Java:ThreadLocal小记
Java:ThreadLocal小记 说明:这是看了 bilibili 上 黑马程序员 的课程 java基础教程由浅入深全面解析threadlocal 后做的笔记 内容 ThreadLocal 介绍 ...
- 面经手册 · 第12篇《面试官,ThreadLocal 你要这么问,我就挂了!》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 说到底,你真的会造火箭吗? 常说面试造火箭,入职拧螺丝.但你真的有造火箭的本事吗,大 ...
- ThreadLocal简单理解
在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...
- Android线程管理之ThreadLocal理解及应用场景
前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...
- [原]Paste.deploy 与 WSGI, keystone 小记
Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...
- Threadlocal使用Case
Threadlocal能够为每个线程分配一份单独的副本,使的线程与线程之间能够独立的访问各自副本.Threadlocal 内部维护一个Map,key为线程的名字,value为对应操作的副本. /** ...
- 多线程映射工具——ThreadLocal
ThreadLocal相当于一个Map<Thread, T>,各线程使用自己的线程对象Thread.currentThread()作为键存取数据,但ThreadLocal实际上是一个包装了 ...
- ThreadLocal 工作原理、部分源码分析
1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...
- ThreadLocal<T>的是否有设计问题
一.吐槽 ThreadLocal<T>明显是.NET从JAVA中来的一个概念,但是这种设计是否出现了问题. 很明显,在JAVA中threadLocal直接是Thread的成员,当然随着th ...
随机推荐
- select多个字段赋值给多个变量
在存储过程中定义了变量v1 int;v2 int;v3 int;从表tab1选择3个字段f1,f2,f3赋值给这三个变量,要如何写 如果单个变量可以 select f1 into v1 from t ...
- NSRangeFromString 测试
官网文档 Returns a range from a textual representation. Declaration SWIFT func NSRangeFromString(_ aStri ...
- geeksforgeeks@ Maximum Index (Dynamic Programming)
http://www.practice.geeksforgeeks.org/problem-page.php?pid=129 Maximum Index Given an array A of int ...
- 一、 使用存储过程实现数据分页(Sql Server 2008 R2)
1.废话不多说了,直接上代码.调用这个存储过程只需要传递 表名,排序字段,搜索字段,以及页码,页码数量,搜索值(可空) create PROCEDURE NewPage --通用的分页存储过程,百万数 ...
- C++11用于计算函数对象返回类型的统一方法
[C++11用于计算函数对象返回类型的统一方法] 模板 std::result_of 被TR1 引进且被 C++11 所采纳,可允许我们决定和使用一个仿函数其回返值的类别.底下,CalculusVer ...
- 网易及新浪IP查询接口
通过IP地址获取对应的地区信息通常有两种方法:1)自己写程序,解析IP对应的地区信息,需要数据库.2)根据第三方提供的API查询获取地区信息. 第一种方法,参见文本<通过纯真IP数据库获取IP地 ...
- XML的特殊字符处理
XML中共有5个特殊的字符,分别是:&<>“’.如果配置文件中的注入值包括这些特殊字符,就需要进行特别处理.有两种解决方法:其一,采用本例中的<![CDATA[ ]]> ...
- [iOS微博项目 - 3.3] - 封装网络请求
github: https://github.com/hellovoidworld/HVWWeibo A.封装网络请求 1.需求 为了避免代码冗余和对于AFN框架的多处使用导致耦合性太强,所以把网 ...
- easyui反选全选和全不选代码以及方法的使用
首先要说明的是,onclick="javascript:这里能写方法的名字,也能写一段JS的代码,但是方法名字要带括号.",其次就是onclick=“这里写的方法名必须存在于本页面 ...
- java正则表达式语法详解及其使用代码实例
原文地址 译者序(下载代码) 正则表达式善于处理文本,对匹配.搜索和替换等操作都有意想不到的作用.正因如此,正则表达式现在是作为程序员七种基本技能之一*,因此学习和使用它在工作中都能达到很高的效率. ...