· 在多线程环境下,每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其它线程。
· ThreadLocal可以放一个线程级别的变量,其本身能够被多个线程共享使用,并且又能够达到线程安全的目的。说白了,ThreadLocal就是想在多线程环境下去保证成员变量的安全。常用的方法有get/set/initialValue方法。
· JDK建议ThreadLocal设置为private static。
· ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的方法都可以非常方便地访问这些资源。
\quad
· Hibernate的Session工具类HibernateUtil。
\quad
· 通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性。
\quad
可以把ThreadLocal理解为一栋全是相同毛坯房的建筑,在创建线程对象时,每个线程都会给自己拿一间房,线程A调用set方法对ThreadLocal变量值的修改相当于对自己的房子进行装修,这当然仅限于自己的房子,对其它线程的房子没有影响,同理每个线程调用get方法也只能展示自己的房子。
\quad
ThreadLocal内部的存储结构类似于Map,Key为线程信息(每个线程都会有唯一的标识),值为存储的数据。
/**
* ThreadLocal:每个线程自身的存储本地、局部区域
* get/set/initialValue
*/
public class ThreadLocalTest01 {
//private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); //默认返回值为null
//使用匿名内部类重写initialValue方法更改初始值
/*private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>() {
@Override
protected Integer initialValue() {
return 200;
}
};*/
//使用Lambda简写
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);
public static void main(String[] args) {
//获取值
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
//设置值
threadLocal.set(99);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
new Thread(new MyRun()).start();
new Thread(new MyRun()).start();
}
public static class MyRun implements Runnable {
@Override
public void run() {
threadLocal.set((int)(Math.random()*99));
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}
}
}
/**
* ThreadLocal:每个线程自身的数据,更改不会影响其它线程
* get/set/initialValue
*/
public class ThreadLocalTest02 {
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1);
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
new Thread(new MyRun()).start();
}
}
public static class MyRun implements Runnable {
@Override
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());
}
}
}
/**
* ThreadLocal:分析上下文环境
* 1、构造器:哪里调用 就属于哪里 找线程体
* 2、run方法:本线程自身的
*
*/
public class ThreadLocalTest03 {
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1);
public static void main(String[] args) {
new Thread(new MyRun()).start();
new Thread(new MyRun()).start();
}
public static class MyRun implements Runnable {
public MyRun() {
threadLocal.set(-100);
//想想下面的语句中当前线程指的是谁
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}
@Override
public void run() {
//想想下面的语句中当前线程指的是谁
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}
}
}
/**
* InheritableThreadLocal:继承上下文环境的数据,拷贝给子线程
*
*/
public class ThreadLocalTest04 {
private static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set(2);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
//线程由main线程开辟,所以继承了main的值
new Thread(()-> {
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
threadLocal.set(200);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}).start();
}
}