您的位置:首页 > 其它

ThreadLocal线程局部变量

2014-09-24 11:00 344 查看

1.ThreadLocal说明

线程内的共享数据:方法,表达式或者是模块,当他们在同一线程上运行,他们访问同一变量,应该访问的是同一数据。将数据与线程绑定到一起。换句话说,我线程内的事在我的线程内完成,不受其他线程的影响。线程内共享同一数据对象。即在线程内共享,在线程外独立。

public Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();threadData.put(Thread.currentthread,data);

ThreadLocal:就相当于一个map,直接向当前线程存取数据。newThreadLocal.set()/get,对于同一个Thread对象而言,一个ThreadLocal对象只能封装一个数据,要封装两个数据则需要两个ThreadLocal独享,若是要封装一百个数据,那么先定义一个对象封装一百个ThreadLocal对象,然后封装这个对象。

ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。

2.ThreadLocal与synchronized的区别

ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。

3.ThreadLocal使用的一般步骤

1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。

2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。

3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。

4.应用code演示

public class ThreadLocalTest {

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();// 多线程共享数据

public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
// 多个线程往该threadLocal中存入值
new Thread(new Runnable() {
@Override
public void run() {
//		synchronized (ThreadLocalTest.class) {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ " has put data :" + data);
threadLocal.set(data);
MyThreadScopeData.getThreadInstance().setName(
"name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
// 多个类中读取threadLocal的值,可以看到多个类在同一个线程中共享同一份数据
new A().get();
new B().get();
//	}
}
}).start();
}
}

/**
* 模拟业务模块A
*
* @author Administrator
*
*/
static class A {
public void get() {
int data = threadLocal.get();
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out
.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + ","
+ myData.getAge());
}
}

/**
* 模拟业务模块B
*
* @author Administrator
*
*/
static class B {
public void get() {
int data = threadLocal.get();
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out
.println("B from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + ","
+ myData.getAge());
}
}
}

class MyThreadScopeData {
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();

public static MyThreadScopeData getThreadInstance() {
MyThreadScopeData instance = map.get();
if (instance == null) {
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}

private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
System.out.println(Thread.currentThread().getName() + " setName :"
+ name);
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
System.out
.println(Thread.currentThread().getName() + " setAge :" + age);
this.age = age;
}
}
控制台输出结果:

Thread-3 has put data :-1350986975
Thread-1 has put data :-1681440308
Thread-2 has put data :-1348632509
Thread-0 has put data :1315014774
Thread-4 has put data :-129193035
Thread-3 setName :name-1350986975
Thread-3 setAge :-1350986975
Thread-0 setName :name1315014774
Thread-0 setAge :1315014774
Thread-4 setName :name-129193035
Thread-4 setAge :-129193035
Thread-2 setName :name-1348632509
Thread-2 setAge :-1348632509
A from Thread-4 get data :-129193035
Thread-1 setName :name-1681440308
A from Thread-4 getMyData: name-129193035,-129193035
A from Thread-0 get data :1315014774
A from Thread-0 getMyData: name1315014774,1315014774
A from Thread-2 get data :-1348632509
A from Thread-2 getMyData: name-1348632509,-1348632509
A from Thread-3 get data :-1350986975
A from Thread-3 getMyData: name-1350986975,-1350986975
Thread-1 setAge :-1681440308
A from Thread-1 get data :-1681440308
B from Thread-4 get data :-129193035
B from Thread-3 get data :-1350986975
B from Thread-0 get data :1315014774
B from Thread-0 getMyData: name1315014774,1315014774
B from Thread-2 get data :-1348632509
B from Thread-2 getMyData: name-1348632509,-1348632509
B from Thread-4 getMyData: name-129193035,-129193035
A from Thread-1 getMyData: name-1681440308,-1681440308
B from Thread-3 getMyData: name-1350986975,-1350986975
B from Thread-1 get data :-1681440308
B from Thread-1 getMyData: name-1681440308,-1681440308


5.web拓展

每一个HTTP请求、都是一个独立的线程,有一个独立的ThreadLocal。利用该特性我们可以利用ThreadLocal进行、HTTP请求生命周期的暂时存取值,不同类之间进行传值。比如传递数据库连接等。至此我们在Web应用不用Scope的变量存放值可以利用以下几种手段:

request、ThreadLocal、session、application等。其作用域大家都知道、就不在此详细说明了。现在说明一下request和ThreadLocal的差别。

1)、存取值方式不同。

request根据KEY存取值、一个request可以存多个值。

ThreadLocal只能存一个值,ThreadLocal的get和set方法没有参数KEY。

2)、使用地方不一样。

request使用在表示层、一般在Action和Servlet中使用。

ThreadLocal在什么地方都可以、一般用在框架基类中比较多、比如存放当前的数据库连接等。

转载请声明出处!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: