在多线程环境下,每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程。
ThreadLocal能够放一个线程级别的变量,其本身能够被多个线程共享使用,并且又能够达到线程安全的目的。说白了,ThreadLocal就是想在多线程环境下去保证成员变量的安全,常用的方法,就是get/set/initialValue方法。
ThreadLocal 最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的方法都可以非常方便地访问这些资源。
ThreadLocal在Hibernate框架中也被用到,具体可以查看Hibernate中的ThreadLocal绑定Session。
JDK建议ThreadLocal声明为为private static。
例:Test类的main方法执行后会创建两个线程,每个线程都会生成一个随机数保存在ThreadLocal中,这样的话就能保证在每个线程中A类和B类中获得的都是本线程私有的数据。
package cn.jingpengchong;
import java.util.Random;
public class Test {
private static ThreadLocal<Integer> tl = new ThreadLocal<>();
public static void main(String[] args) {
for(int i = 1; i <= 2; i ++) {
new Thread(() -> {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + " has get data: " + data);
tl.set(data);
new A().get();
new B().get();
}).start();
}
}
private static class A{
public void get() {
int data = tl.get();
System.out.println("A from " + Thread.currentThread().getName() + " has get data: " + data);
}
}
private static class B{
public void get() {
int data = tl.get();
System.out.println("B from " + Thread.currentThread().getName() + " has get data: " + data);
}
}
}
运行结果如下:
例:如果不使用ThreadLocal保存数据,而是企图用普通的int类型的变量存储数据,结果会怎样呢?
package cn.jingpengchong;
import java.util.Random;
public class Test {
private static int data;
public static void main(String[] args) {
for(int i = 1; i <= 2; i ++) {
new Thread(() -> {
data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + " has get data: " + data);
new A().get();
new B().get();
}).start();
}
}
private static class A{
public void get() {
System.out.println("A from " + Thread.currentThread().getName() + " has get data: " + data);
}
}
private static class B{
public void get() {
System.out.println("B from " + Thread.currentThread().getName() + " has get data: " + data);
}
}
}
结果如下:一个线程就会访问到另一个线程的数据,这样是很不安全的。