轻松突击ThreadLocal
来源:互联网 发布:windows 10如何截图 编辑:程序博客网 时间:2024/06/12 15:43
本文出自
代码大湿
代码大湿
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(); }}
客户端中将
//不使用ThreadLocalprivate static NumberConstruct numberConstruct=new ConcreteNumberConstructA();
替换为
//使用ThreadLocalprivate 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(); }}
将客户端中的
//使用ThreadLocalprivate static NumberConstruct numberConstruct=new ConcreteNumberConstructB();
替换为
//使用自己的MyThreadLocalprivate static NumberConstruct numberConstruct=new ConcreteNumberConstructC();
结果:
总结:如果你需要多个线程之间共享变量的时候,想下是否需要考虑线程安全的问题,如果需要则可以使用ThreadLocal简单解决。
本文出自
代码大湿
代码大湿
0 0
- 轻松突击ThreadLocal
- 突击Spring
- 士兵突击
- 士兵突击
- 汉王突击
- 突击斯坦福大学
- 技能突击
- 突击EJB
- 士兵突击
- 《士兵突击》
- 突击战
- 士兵突击
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- View树的绘图流程
- MongoDB学习笔记-数据导入Excel文件
- LeetCode OJ(6.ZigZag Conversion)
- mybatis---创建序列
- 爬虫之路——Day3
- 轻松突击ThreadLocal
- python中的五种异常处理机制介绍
- java nio理解(3)
- 操作系统中的信号量(sema)与互斥(mutex)
- 构造函数你真的看懂了吗
- 《图数据库》(人民邮电出版社)读书笔记一、二
- Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)
- True Nobility(《真正的高贵》)By Ernest Hemingway(海明威)
- C++11新特性