本文出自

代码大湿

代码大湿

ThreadLocal是用来保存线程的本地变量,可以保证每个线程都有一个自己的变量(包括static变量)。

本文所有代码请点击我

1 看个实际场景。

我们要设计一个序列号生成器,每个线程之间对序列号的获取是是隔离的。初始我们可能会这样设计。使用一个static变量。

首先有一个序列号生成器的接口

package ThreadLocal;
/*
*2016年8月28日 下午2:48:17
*@Author Pin-Wang
*@E-mail 1228935432@qq.com
*/
public interface NumberConstruct {
public int get();
}

生成器的具体实现是:

package ThreadLocal;
/*
*2016年8月28日 下午2:49:34
*@Author Pin-Wang
*@E-mail 1228935432@qq.com
*/
public class ConcreteNumberConstructA implements NumberConstruct{
private volatile static int n=0;
@Override
public synchronized int get() {
return ++n;
}
}

客户端:

package ThreadLocal;

/*
*2016年8月28日 下午2:46:10
*@Author Pin-Wang
*@E-mail 1228935432@qq.com
*/
public class Test {
//不使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructA();; //使用ThreadLocal
//private static NumberConstruct numberConstruct=new ConcreteNumberConstructB();; public static void main(String[] args){
//每个线程获取三个序列号
Runnable task=new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+" "+numberConstruct.get());
}
}
};
//开启是哪个线程
Thread t1=new Thread(task);
Thread t2=new Thread(task);
Thread t3=new Thread(task);
t1.start();
t2.start();
t3.start();
} }

结果;

可以看到3个线程之间都共享了static变量(没有考虑到共享资源的线程安全),这并不是我们想要的结果。

所以我们用ThreadLocal解决:

生成器的具体实现:

package ThreadLocal;
/*
*2016年8月28日 下午2:49:34
*@Author Pin-Wang
*@E-mail 1228935432@qq.com
*/
public class ConcreteNumberConstructB implements NumberConstruct{
private static ThreadLocal<Integer> n=new ThreadLocal<Integer>(){ @Override
protected Integer initialValue() {
return 0;
}}; @Override
public int get() {
n.set(n.get()+1);
return n.get();
}
}

客户端中将

//不使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructA();

替换为

//使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructB();

其它均不变

结果:

这是我们想要的结果。可以看到对于每个共享变量,每个线程之间都有自己的副本,线程之间是隔离的。

2 实现我们自己的ThreadLocal。

ThreadLocal内部其实非常简单。主要是一个同步的HashMap(因为涉及到多线程共享资源),主要有以下几个方法;

//得到当前线程的副本值
get() //设定当前线程的副本值
set() //删除当前线程的副本值
remove() //初始化当前线程的副本值
initialValue()

code;

MyThreadLocal类

package ThreadLocal;
/*
*2016年8月28日 下午3:57:17
*@Author Pin-Wang
*@E-mail 1228935432@qq.com
*/ import java.util.concurrent.ConcurrentHashMap; public class MyThreadLocal<T> {
private ConcurrentHashMap<Thread, T> map=new ConcurrentHashMap<>();
//initialValue()
protected T initialValue(){
//返回null,由子类指定初始值
return null;
} //set()
public void set(T value){
map.put(Thread.currentThread(), value);
}
//get()
public T get(){
if(!map.containsKey(Thread.currentThread())){
T value=initialValue();
map.put(Thread.currentThread(), value);
}
return map.get(Thread.currentThread());
}
//remove()
public void remove(){
map.remove(Thread.currentThread());
} }

ConcreteNumberConstructC 类

package ThreadLocal;
/*
*2016年8月28日 下午2:49:34
*@Author Pin-Wang
*@E-mail 1228935432@qq.com
*/
public class ConcreteNumberConstructC implements NumberConstruct{
private MyThreadLocal<Integer> n=new MyThreadLocal<Integer>(){ @Override
protected Integer initialValue() {
return 0;
}}; @Override
public int get() {
n.set(n.get()+1);
return n.get();
}
}

将客户端中的

//使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructB();

替换为

//使用自己的MyThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructC();

结果:

总结:如果你需要多个线程之间共享变量的时候,想下是否需要考虑线程安全的问题,如果需要则可以使用ThreadLocal简单解决。

本文出自

代码大湿

代码大湿

轻松突击ThreadLocal的更多相关文章

  1. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  2. 谈谈Java中的ThreadLocal

    什么是ThreadLocal ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本.通过ThreadLocal可以将对象的 ...

  3. ThreadLocal实现方式&使用介绍—无锁化线程封闭

    原文出处: xieyu_zy 虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以 ...

  4. Android消息机制之ThreadLocal的工作原理

    来源: http://blog.csdn.net/singwhatiwanna/article/details/48350919 很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI ...

  5. ThreadLocal实现方式&使用介绍---无锁化线程封闭

    虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...

  6. Java中ThreadLocal无锁化线程封闭实现原理

    虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...

  7. 一个故事讲明白线程的私家领地:ThreadLocal

    张大胖上午遇到了一个棘手的问题,他在一个AccountService中写了一段类似这样的代码: Context ctx = new Context(); ctx.setTrackerID(.....) ...

  8. 带你了解源码中的 ThreadLocal

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 这次想来讲讲 ThreadLocal 这个很神奇的东西,最开始接触到这个是看了主席的<开发艺术探索>,后来是在研究 Vi ...

  9. Java ThreadLocal (Java代码实战-006)

    ThreadLocal解决什么问题 由于 ThreadLocal 支持范型,如 ThreadLocal< StringBuilder >,为表述方便,后文用 变量 代表 ThreadLoc ...

随机推荐

  1. 56. Merge Intervals

    题目: Given a collection of intervals, merge all overlapping intervals. For example,Given [1,3],[2,6], ...

  2. Redis是什么?

    1. Redis是什么 这个问题的结果影响了我们怎么用Redis.如果你认为Redis是一个key value store, 那可能会用它来代替MySQL;如果认为它是一个可以持久化的cache, 可 ...

  3. javac编译过程

    编译器把一种语言规范转化为另一种语言规范的这个过程需要哪些步骤:

  4. UVa 10892 (GCD) LCM Cardinality

    我一直相信这道题有十分巧妙的解法的,去搜了好多题解发现有的太过玄妙不能领会. 最简单的就是枚举n的所有约数,然后二重循环找lcm(a, b) = n的个数 #include <cstdio> ...

  5. bzoj1832: [AHOI2008]聚会

    写过的题... #include<cstdio> #include<cstring> #include<iostream> #include<algorith ...

  6. ASP.NET MVC @helper使用说明

    简单的 @helper 方法应用场景 Razor中的@helper语法让您能够轻松创建可重用的方法,此方法可以在您的视图模板中封装输出功能.他们使代码能更好地重用,也使代码更具有可读性. 在我们定义@ ...

  7. python模拟http请求2

    发现了一个非常好用的第三方module:requests,模拟接口非常简单. 详细了解请移步:http://docs.python-requests.org/en/latest/ 非常不错 #!cod ...

  8. Delphi反汇编内部字符串处理函数/过程不完全列表

    Delphi反汇编内部字符串处理函数/过程不完全列表 名称 参数 返回值 作用 等价形式 / 备注   _PStrCat EAX :目标字符串 EDX :源字符串 EAX 连接两个 Pascal 字符 ...

  9. 运维角度浅谈MySQL数据库优化(转)

    一个成熟的数据库架构并不是一开始设计就具备高可用.高伸缩等特性的,它是随着用户量的增加,基础架构才逐渐完善.这篇博文主要谈MySQL数据库发展周期中所面临的问题及优化方案,暂且抛开前端应用不说,大致分 ...

  10. (转)c & c++内存分配

    一.预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于 数据结构中的栈. ...