您的位置:首页 > 其它

ThreadLocal和线程的普通成员变量究竟有什么区别?

2018-02-25 23:40 351 查看

问题由来:

最近在看多线程的知识,有提到ThreadLocal是一种线程局部变量,每个线程都有相对独立的变量初始化拷贝,是一种以空间换时间的做法。

那么问题来了,

1. 它和在线程代码里直接写一个普通成员变量有什么区别呢?

2. 它真的能“以空间换时间”吗?

问题1的思考:

问题:它和在线程代码里直接写一个普通成员变量有什么区别呢?

ThreadLocal和线程的普通成员变量都是线程安全的,我觉得这是毫无疑问的。因为每个线程都有一个threadLocals,这个里面就是一个ThreadLocalMap,而ThreadLocal对象就是map的key。

这样就可以写出非常优雅的代码了,因为传入一个外部的ThreadLocal对象,或者是线程的static对象,只要你没有对它进行过初始化,那么你通过threadLocal.get()出来的就是null。这就表明,一个threadLocal对象在其他线程里面调用了set()赋值,并不会影响到另一个线程。

话又说回来了,ThreadLocal和线程的普通成员变量到底有什么区别呢?

我的理解是,普通成员变量的初始化对这个线程本身是高度耦合的,我必须要知道这个线程是哪个,必须知道这个普通成员变量名是什么才能进行赋值。

而ThreadLocal则不需要,只需要声明好泛型的类型,定义好初始化函数,或者在自己定义的getValue方法里判断ThreadLocal.get()==null?是则调用ThreadLocal.set()方法进行初始化。

就比如这个例子:

public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public Integer getNextNum() {
//将tl的值获取后加1,并更新设置t1的值
tl.set(tl.get() + 1);
return tl.get();
}
}


/**
* 测试线程
*/
public class TestThread extends Thread {
private MyThreadLocal tlt = new MyThreadLocal();

public TestThread(MyThreadLocal tlt) {
this.tlt = tlt;
}

@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + tlt.getNextNum());
}
}
}


/**
* ThreadLocal测试
*
* @author leizhimin 2010-1-5 10:43:48
*/
public class Test {
public static void main(String[] args) {
MyThreadLocal tlt = new MyThreadLocal();
Thread t1 = new TestThread(tlt);
Thread t2 = new TestThread(tlt);
Thread t3 = new TestThread(tlt);
Thread t4 = new TestThread(tlt);
t1.start();
t2.st
b9b0
art();
t3.start();
t4.start();

}
}


测试结果:

Thread-0  1
Thread-1  1
Thread-0  2
Thread-1  2
Thread-0  3
Thread-1  3
Thread-2  1
Thread-3  1
Thread-2  2
Thread-3  2
Thread-2  3
Thread-3  3


由此可见,线程的代码里根本就不需要对ThreadLocal里的变量的初始化操心,这些都可以由外部的工具类完成,而工具类里也不需要管是哪个线程调用的。

我觉得这就是ThreadLocal最强大的地方!

问题2的思考:

问题:它真的能“以空间换时间”吗?

我觉得这个一空间换时间是针对使用static sycronized的变量而言的。

有的线程要用到数据库连接的condition,或者是session。这些都是线程不安全的,如果一个类只有一个全局的static变量,那么是一定要用同步来控制的。

那在高并发环境下的阻塞等待是不能容忍的。

所以使用ThreadLocal可以在每个线程都能初始化一下,就解决了异步问题。

所以我觉得ThreadLocal所说的“以空间换时间”,是针对static sycronized的方式来说的。

这就是我对ThreadLocal的思考,可能有些问题,还请高手指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐