简介
- 在多线程环境下,每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程。
- ThreadLocal能够放一个线程级别的变量,其本身能够被多个线程共享使用,并且又能够达到线程安全的目的。说白了,ThreadLocal就是想在多线程环境下去保证成员变量的安全,常用的方法,就是get/set/initialValue()方法。
- JDK建议ThreadLocal定义为private static
- ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的方法都可以非常方便地访问这些资源。
(1)Hibernate的Session工具类HibernateUtil
(2)通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性。
测试
- 基本使用方法
code:
/**
* ThreadLocal:每个线程自身的存储本地、局部区域
* get/set/initValue
* @author dxt
*
*/
public class ThreadLocalTest01 {
//创建一个线程空间, 每个线程都在里面有一个只有自己可以访问的"保险箱"
//public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
//2. 更改线程空间的初始值,要重写initialValue()方法
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
protected Integer initialValue(){
return 200; //初始值由null变为200
}
};
public static void main(String[] args){
//1. 打印 主线程 的初始值, 因为是Integer而不是int,所以会打印null,而不是0
System.out.println(Thread.currentThread().getName() + "--" + threadLocal.get());
//3. 设置初始化值
threadLocal.set(100);
System.out.println(Thread.currentThread().getName() + "--" + threadLocal.get());
//4. 在main线程外,建立新的线程,两个线程间的值互不影响
new Thread(new MyRun()).start();
//5. 每个线程在ThreadLocal内有自己独立的空间
new Thread(new MyRun()).start();
}
/**
* 静态内部类
* @author dxt
*
*/
public static class MyRun implements Runnable{
public void run(){
threadLocal.set((int)(Math.random()*100));
System.out.println(Thread.currentThread().getName() + "--" + threadLocal.get());
}
}
}
result:
2. 每个线程有自己的存储区域
code:
/**
* 每个线程有自己的存储区域
* @author dxt
*
*/
public class ThreadLocalTest02 {
//创建线程空间
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
protected Integer initialValue(){
return 1; //将数据初始化为1,可以认为每个线程都有一个属于自己的1
}
};
public static void main(String[] args){
//建立5个线程
for(int i=0; i<5; i++){
new Thread(new MyRun()).start();
}
}
public static class MyRun implements Runnable{
public void run(){
Integer left = threadLocal.get();
System.out.println(Thread.currentThread().getName() + " 得到了"+ left+"个苹果");
threadLocal.set(left-1);
System.out.println(Thread.currentThread().getName() + " 还剩下"+ threadLocal.get()+"个苹果");
}
}
}
result:
3. 分析上下文
code:
/**
* 分析ThreadLocal的上下文, 环境
* @author dxt
*
*/
public class ThreadLocalTest03 {
//创建线程空间
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
protected Integer initialValue(){
return 1; //将数据初始化为1,可以认为每个线程都有一个属于自己的1
}
};
public static void main(String[] args){
new Thread(new MyRun()).start();
}
public static class MyRun implements Runnable{
public MyRun(){
threadLocal.set(100); //是对main线程进行更改
//输出调用MyRun()构造函数的线程的信息
System.out.println(Thread.currentThread().getName()+"--"+threadLocal.get());
}
public void run(){
System.out.println(Thread.currentThread().getName()+"--"+threadLocal.get());
}
}
}
result:
4. InheritableThreadLocal
code:
/**
* InheitableThreadLocal:继承上下文环境的数据,复制一份数给子线程,在子线程中可以更改
* 但不影响原数据
* @author dxt
*
*/
public class ThreadLocalTest04 {
public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>();
public static void main(String[] args){
threadLocal.set(2);
System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());
new Thread(new Runnable(){
public void run(){ //若是ThreadLocal会是null
System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());
}
}).start();
}
}
result: