本文出自

代码大湿

代码大湿

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. 数据抓取的艺术(一):Selenium+Phantomjs数据抓取环境配置

     数据抓取的艺术(一):Selenium+Phantomjs数据抓取环境配置 2013-05-15 15:08:14 分类: Python/Ruby     数据抓取是一门艺术,和其他软件不同,世界上 ...

  2. Java API —— Set接口 & HashSet类 & LinkedHashSet类

    1.Set接口     1)Set接口概述         一个不包含重复元素的 collection,无序(存储顺序和取出顺序不一致),唯一.  (List有序,即存储顺序和取出顺序一致,可重复) ...

  3. 写Java程序让Jvm崩溃

    package jvm; public class HeapCrash { public static void main(String[] args) { //Object[] o = {“abc” ...

  4. python小问题记录:

    numpy.chararray.flatten chararray.flatten(order='C') Return a copy of the array collapsed into one d ...

  5. (三)C#关于txt文件的读取和写入

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  6. MariaDB10.2.X-新特性2-支持check约束and with as

    前几天写了一篇MariaDB10.2支持分析函数,大家印象中MySQL不支持with as ,check约束,那么MariaDB10.2也同样给你惊喜 1.with as MariaDB [test1 ...

  7. bat拷贝文件

    最近在部署服务器的时候,需要用到把一个站点文件拷贝到其他站点.一个一个手动copy太累人了,写了个简单的批处理文件,基本能达到目的,具体怎么做呢: 1.把需要拷贝到各个站点的文件,单独放到一个目录下. ...

  8. IOSTimer的例子留个备注

    1.创建一个定时器 ,以下是便利构造器方法,+ scheduledTimerWithTimeInterval:invocation:repeats:+ scheduledTimerWithTimeIn ...

  9. 利用Java自带的MD5加密java.security.MessageDigest;

    MD5加密算法,即"Message-Digest Algorithm 5(信息-摘要算法)",它由MD2.MD3.MD4发展而来的一种单向函数算法(也就是HASH算法),它是国际著 ...

  10. BZOJ 2179 FFT快速傅里叶

    fft. #include<set> #include<map> #include<ctime> #include<queue> #include< ...