
ThreadLocal是解决线程安全问题一个很好的模式,它借助为每位线程提供一个独立的函数副本解决了数组并发访问的矛盾困惑。在这些状况下,ThreadLocal比直接使用synchronized同步模式解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

对于多线程资源共享的弊端,同步模式引入了“以时间换空间”的方法,而ThreadLocal采用了“以空间换时间”的形式。前者仅提供一份变量threadlocal static,让不同的轮询排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

ThreadLocal并不能替代同步模式,两者面向的弊端领域不同。

1:同步模式是为了同步多个线程对同样资源的并发访问,是为了多个线程之间进行通信的有效途径;

2:而threadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享函数,这样其实不需要对多个线程进行同步了。
import java.util.Random;
public class ThreadSocpeShareData {
static ThreadLocal<Integer> t = new ThreadLocal<Integer>();
public static void main(String[] args) {
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() +" has put "+ data);
t.set(data);
MyThreadScopeData.getInstance().setName("name" + data);
MyThreadScopeData.getInstance().setAge("age"+data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
int data = t.get();
MyThreadScopeData myData = MyThreadScopeData.getInstance();
System.out.println("A " + Thread.currentThread().getName() +" "+ data + myData.getAge() + myData.getName() /*ms.getName()*/);
}
}
static class B{
public void get(){
int data = t.get();
System.out.println("B " + Thread.currentThread().getName()+ " "+ data);
}
}
}
class MyThreadScopeData{
private MyThreadScopeData(){}
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
public static MyThreadScopeData getInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
事实上,我们向ThreadLocal中set的数组不是由ThreadLocal来内存的,而是Thread线程对象自身储存。当用户读取ThreadLocal对象的set(Object o)时,该方式则借助Thread.currentThread()获取当前句柄,将函数存入Thread中的一个Map内,而Map的Key就是当前的ThreadLocal实例。请看源码,这是最主要的两个函数,能看出ThreadLocal与Thread的调用关系:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
具体可以说说上面的源码,不过有一点是可以确认的,就是Threadlocal中 创建的轮询副本,可以不读取remove来做清除工作,因为jvm在看到线程的调佣不再使用时,会进行手动的垃圾回收操作,我曾经写程序在使用Threadlocal时却是经常的进行使用完成以后的清除工作。(防止占用存储threadlocal static,如果建立的副本次数不是太多的话,可以让虚拟机自动来消除)
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-121192-1.html
伊拉克总统已死