轻松突击ThreadLocal
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的更多相关文章
- Android线程管理之ThreadLocal理解及应用场景
前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...
- 谈谈Java中的ThreadLocal
什么是ThreadLocal ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本.通过ThreadLocal可以将对象的 ...
- ThreadLocal实现方式&使用介绍—无锁化线程封闭
原文出处: xieyu_zy 虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以 ...
- Android消息机制之ThreadLocal的工作原理
来源: http://blog.csdn.net/singwhatiwanna/article/details/48350919 很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI ...
- ThreadLocal实现方式&使用介绍---无锁化线程封闭
虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...
- Java中ThreadLocal无锁化线程封闭实现原理
虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...
- 一个故事讲明白线程的私家领地:ThreadLocal
张大胖上午遇到了一个棘手的问题,他在一个AccountService中写了一段类似这样的代码: Context ctx = new Context(); ctx.setTrackerID(.....) ...
- 带你了解源码中的 ThreadLocal
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 这次想来讲讲 ThreadLocal 这个很神奇的东西,最开始接触到这个是看了主席的<开发艺术探索>,后来是在研究 Vi ...
- Java ThreadLocal (Java代码实战-006)
ThreadLocal解决什么问题 由于 ThreadLocal 支持范型,如 ThreadLocal< StringBuilder >,为表述方便,后文用 变量 代表 ThreadLoc ...
随机推荐
- 248. Strobogrammatic Number III
题目: A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at ups ...
- Maven那点事儿(Eclipse版)
Maven那点事儿(Eclipse版) 前言: 由于最近工作学习,总是能碰到Maven的源码.虽然平时工作并不使用Maven,但是为了学习一些源码,还是必须要了解下.这篇文章不是一个全面的Mave ...
- Tomcat目录介绍以及运行时寻找class的顺序
来自:http://blog.csdn.net/lihai211/article/details/6651977 Tomcat下的文件目录 /bin:存放启动和关闭tomcat的脚本文件: /conf ...
- [Codeforces137B]Permutation(贪心?思路?,水题)
题目链接:http://codeforces.com/contest/137/problem/B 给n个数字,要求修改成1~n的全排列数中的一个,修改的次数尽可能少,问最少需要修改几个数. 记下数组里 ...
- 对github中项目进行更新
进入本地仓库文件夹,我的仓库名是tufujiegit,然后 进入 git clone 接着将先前记录下来的地址复制到后面,回车 将下载github中该仓库的所有文件及文件夹,包括.git文件夹在内 ...
- [LeetCode#249] Group Shifted Strings
Problem: Given a string, we can "shift" each of its letter to its successive letter, for e ...
- struts2 获取前台表单的值?? 原理??
struts2中,在ACTION中申明一个变量 private string 变量名:然后设置变量名 的get/set方法: 在运行的时候struts2会自动获取. 比如:jsp 页面中有个文本框&l ...
- 原创-兼容IE8的placeholder
!function (o) { o.fn.extend({ PlaceHolder: function () { var _isEmpty = function (val) { return (val ...
- [反汇编练习] 160个CrackMe之013
[反汇编练习] 160个CrackMe之013. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
- Azure SQL 数据库:新服务级别问答
ShawnBice 2014 年 5 月 1 日上午 11:10 本月初,我们庆祝了SQL Server 2014 的推出,并宣布正式发布分析平台系统,同时分享了智能系统服务预览版.Quentin ...