轻松突击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 ...
随机推荐
- 前端自动化工具:Grunt使用教程
1.下载node.js,然后将node.exe文件所在的目录加入path环境变量 2.安装npm管理工具 2.1.下载npm源码,解压到npm文件夹里,不要把npm放在和node.exe相同的文件夹 ...
- 高性能Web框架Zend Framework
Zend Framework (ZF)是用 PHP 5.3及更高版本来开发 Web 程序和服务的开源框架.ZF用100% 面向对象编码实现. ZF的组件结构独一无二,每个组件几乎不依靠其他组件.这样的 ...
- js问题总结
.removeClass(" ") 移除一个css样式 $("#popUpBox i").removeClass("channel_icon" ...
- 构建linux内核源码树
编写驱动程序时,需要内核源码树的支持.内核源码树时从内核源代码编译得到的.下面开始构造内核源代码的步骤.以Ubuntu为例子 1. 下载内源代码,位置www.kernel.org. (注意:源码树内核 ...
- 使用 GIT 获得Linux Kernel的代码并查看,追踪历史记录
Linux kernel 的官方 GIT地址是: http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git 可以从这个地 ...
- Android权限安全(9)Android权限特点及权限管理服务AppOps Service
Android权限特点 权限管理服务AppOps Service 图中元素介绍: Ignore 是不提示的,Allow 是允许,Reject 是拒绝 Client是一个使用sms 的应用, AppOp ...
- npm在项目目录安装插件需要使用sudo
今天使用node的npm安装插件的时候遇到一个问题,那就是在项目目录里面安装插件的时候,必须使用超级用户(sudo)执行才会安装成功,否则会报如下错误: 以安装 gulp-uglify 为例 $ np ...
- org/apache/commons/discovery/tools/DiscoverSingleton
是编写的调用web service服务器的客户端程序编译时出错. Exception in thread "main" java.lang.NoClassDefFoundError ...
- bzoj3555: [Ctsc2014]企鹅QQ
将字符串hash.不难写.然而1.注意用longlong2.数组大小注意...3.似乎别人都用的unsigned long long ?. #include<cstdio> #includ ...
- Web网站的性能测试工具
随着Web 2.0技术的迅速发展,许多公司都开发了一些基于Web的网站服务,通常在设计开发Web应用系统的时候很难模拟出大量用户同时访问系统的实际情况,因此,当Web网站遇到访问高峰时,容易发生服务器 ...