Java ThreadLocal
参考 http://www.cnblogs.com/alphablox/archive/2013/01/20/2869061.html
参考 http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/
一、定义
ThreadLocal就是对直接在thread中申明一个对象这种行为的封装,让调用者看起来就像静态变量一样。这样可以避免反复的申请和释放空间带来的性能损耗。
ThreadLocal在其内部定义了一个ThreadLocalMap,每当一个线程调用ThreadLocal的get方法时,它就会去map中寻找以该线程id为key的值,如果没找到,就会调用initialValue() 方法初始化该值并插入map,同时返回该值。
ThreadLocal在JDK中是这么定义的:
This class provides thread-local variables. These variables differ from
their normal counterparts in that each thread that accesses one (via its
{@code get} or {@code set} method) has its own, independently initialized
copy of the variable. {@code ThreadLocal} instances are typically private
static fields in classes that wish to associate state with a thread (e.g.,
a user ID or Transaction ID).
翻译过来大致是这样的:
ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程的上下文。
可以总结为一句话:
ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
也就是说,ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。
二、代码实战
1、MyThreadLocal.java
public class MyThreadLocal {
public static final void log(String msg) {
System.out.println(Thread.currentThread().getId() + ". " + msg);
}
public static final ThreadLocal<HashMap<Integer, Integer>> threadLocal = new ThreadLocal<HashMap<Integer, Integer>>() {
//每一次在新的线程中调用threadLocal.get()时,都会调用到该方法,初始化threadLocalMap中key为当前线程id的值
protected HashMap<Integer, Integer> initialValue() {
log("threadLocal_initialValue");
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(-1, -1);
return map;
};
};
public class MyRunnable implements Runnable {
int num;
public MyRunnable(int num) {
this.num = num;
}
@Override
public void run() {
HashMap<Integer, Integer> map = threadLocal.get();
log("before run " + map.toString());
int value;
for (int i = 0; i < 5; i++) {
value = num * 10 + i;
map.put(i, value);
log("map_put (" + i + "," + value + ")");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log("after_put " + map.toString());
HashMap<Integer, Integer> map1 = new HashMap<Integer, Integer>();
map1.put(100, 100);
//将新的map设置为threadLocalMap中key为当前线程id的值,下次通过get(),取的也是当前线程id的值
threadLocal.set(map1);
log("threadLocal_set " + threadLocal.get().toString());
log("before threadLocal_remove ");
//调用threadlocal.remove方法后,会执行initialValue方法,重新初始化map
threadLocal.remove();
HashMap<Integer, Integer> map2 = threadLocal.get();
log("after threadLocal_remove " + (map2 == null ? "map = null" : map2.toString()));
}
}
public MyThreadLocal() {
log("MyThreadLocal init");
}
class ClassA{
public String name;
public ClassA() {
log("ClassA init");
}
}
public static final ThreadLocal<MyThreadLocal> threadLocalTest1 = new ThreadLocal<MyThreadLocal>();
public static final ThreadLocal<ClassA> threadLocalTest2 = new ThreadLocal<ClassA>();
public void run() {
log("run");
for (int i = 0; i < 3; i++) {
// 注意:这里如果只是执行 new MyRunnable(i).run();方法,那么运行环境依然是主线程
new Thread(new MyRunnable(i)).start();
}
}
}
2、执行方法
public static void main(String[] args) {
//threadlocat.get()获取的值也有可能为null
MyThreadLocal mThreadLocal = MyThreadLocal.threadLocalTest1.get();//null
ClassA mClassA = MyThreadLocal.threadLocalTest2.get();//null
System.out.println("localThreadTest<MyThreadLocal>.get() " + (mThreadLocal == null?"is null":"not null"));
System.out.println("localThreadTest<ClassA>.get() " + (mClassA == null?"is null":"not null"));
mThreadLocal = new MyThreadLocal();
MyThreadLocal.log("main_thread");
mThreadLocal.run();
}
三、运行截图
相关文章
- MySQL_(Java)【连接池】简单在JDBCUtils.java中创建连接池
- Java 开发环境配置--eclipse工具进行java开发
- 【异常】javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
- Java实现 LeetCode 331 验证二叉树的前序序列化
- java实现第六届蓝桥杯星系炸弹
- Java实现One-way traffic(单向交通)
- Java实现最优二叉查找树
- Java实现 蓝桥杯VIP 算法训练 方格取数
- Java实现 蓝桥杯VIP 基础练习 完美的代价
- java 11 标准Java异步HTTP客户端
- 【JAVA】Java 异常中e的getMessage()和toString()方法的异同
- 【JAVA】 04-Java中的多线程
- [Linux] Install java and add JAVA_HOME, PATH
- Eclipse 报 “Exception in thread "main" java.lang.OutOfMemoryError: Java heap space ”错误的解决办法
- 深入理解JAVA虚拟机--Idea远程执行本地Java代码
- Java 关于java.util.LinkedHashMap cannot be cast to 实体类问题答案
- Java中String类的concat方法___java的String字符串的concat()方法连接字符串和“+“连接字符串解释
- java.lang.reflect.Filed.class中setInt与set的区别
- Java:Files类读取写入文件
- Java笔记:ThreadLocal和压力测试
- Java通过PDF模板导出数据 adobe acrobat的PDF编辑器 itextpdf java导出文件输出流
- Java 异常解决之java.lang.IllegalArgumentException: Comparison method violates its general contract!
- Java如何获取正在运行的线程的名称?
- JAVA源文件中是否可以包括多个类,有什么限制
- AWT是Java最早出现的图形界面,但很快就被Swing所取代
- Java学习笔记基础(下)
- 【java】Java 抽象类
- 【java】Java 继承