ThreadfLocal用于实现线程内的数据共享,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据(如事务处理中数据库链接的共享,可以实现事务控制),static变量是在jvm里只有一份,无法达到每个线程内数据隔离的效果,而ThreadLocal则从另一个角度来解决多线程的并发导致的数据安全问题,ThreadLocal将需要保护的对象保存在了线程内部,从而不与其它线程分享,这种线程级隔离避免了线程并发访问问题。
因为每一个线程都独立拥有一个对象,该对象只能被自己访问到,从而也就没有必要对该对象的进行同步控制了。
在编写多线程代码时,可以把线程不安全的变量封装进ThreadLocal中,从而避开同步提高性能,当然,要视实际情况而定。
示例代码:
import java.util.Random;
class Student {
String name;
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
}
class DataCenter {
private static DataCenter instance = new DataCenter();
static DataCenter getInstance() {
return instance;
}
/**
* 不同的线程虽然共享了同一个共享的studentThreadLocal,
* 但是其值Student是保存在各个线程内部的是不共享的,这就是线程隔离效果
*/
ThreadLocal<Student> studentThreadLocal = new ThreadLocal<Student>();// 第一个 ThreadLocal
Student getStudent() {
Student student = studentThreadLocal.get();
if (student == null) {
System.out.println("每个线程只会在此初始化一次,本次初始化线程:" + Thread.currentThread().getName());
student = new Student();
student.setName("姓名" + Thread.currentThread().getName());
studentThreadLocal.set(student);
}
return student;
}
}
class ThreadLocalTest extends Thread {
@Override
public void run() {
String currentThreadName = Thread.currentThread().getName();
for (int i = 1; i <= 3; i++) {
try {Thread.sleep(new Random().nextInt(500));} catch (Exception e) {}
Student student = DataCenter.getInstance().getStudent();
System.out.println(currentThreadName + " 第" + i + "次获取姓名: " + student.getName());
}
}
}
public class Test {
public static void main(String[] args) {
new ThreadLocalTest().start();
new ThreadLocalTest().start();
}
}
输出:
每个线程只会在此初始化一次,本次初始化线程:Thread-1
Thread-1 第1次获取姓名: 姓名Thread-1
每个线程只会在此初始化一次,本次初始化线程:Thread-0
Thread-0 第1次获取姓名: 姓名Thread-0
Thread-0 第2次获取姓名: 姓名Thread-0
Thread-1 第2次获取姓名: 姓名Thread-1
Thread-0 第3次获取姓名: 姓名Thread-0
Thread-1 第3次获取姓名: 姓名Thread-1
可以看出,两个线程,一共只进行了两次对象创建,之后每个线程都只访问到自己之前创建的对象(同线程打印student.getName()相同)。

被折叠的 条评论
为什么被折叠?



