首页 / 软件开发 / JAVA / Java多线程同步问题的探究(五)
Java多线程同步问题的探究(五)2012-07-24 BlogJava X-Spirit五、你有我有全都有—— ThreadLocal如何解决并发安全性?前面我们介绍了Java当中多个线程抢占一个共享资源的问题。但不论是同步还是重入锁,都不能实实在在的解决资源紧缺的情况,这些 方案只是靠制定规则来约束线程的行为,让它们不再拼命的争抢,而不是真正从实质上解决他们对资源的需求。在JDK 1.2当中,引入了java.lang.ThreadLocal。它为我们提供了一种全新的思路来解决线程并发的问题。但是他的名字难免让我们望 文生义:本地线程?什么是本地线程?本地线程开玩笑的说:不要迷恋哥,哥只是个传说。其实ThreadLocal并非Thread at Local,而是LocalVariable in a Thread。根据WikiPedia上的介绍,ThreadLocal其实是源于一项多线程技术,叫做Thread Local Storage,即线程本地存储技术。不仅仅是Java ,在C++、C#、.NET、Python、Ruby、Perl等开发平台上,该技术都已经得以实现。当使用ThreadLocal维护变量时,它会为每个使用该变量的线程提供独立的变量副本。也就是说,他从根本上解决的是资源数量的问题 ,从而使得每个线程持有相对独立的资源。这样,当多个线程进行工作的时候,它们不需要纠结于同步的问题,于是性能便大大提升。但 资源的扩张带来的是更多的空间消耗,ThreadLocal就是这样一种利用空间来换取时间的解决方案。说了这么多,来看看如何正确使用ThreadLocal。通过研究JDK文档,我们知道,ThreadLocal中有几个重要的方法:get()、set()、remove()、initailValue(),对应的含义分别是:返回此线程局部变量的当前线程副本中的值、将此线程局部变量的当前线程副本中的值设置为指定值、移除此线程局部变量当前线程的 值、返回此线程局部变量的当前线程的“初始值”。还记得我们在第三篇的上半节引出的那个例子么?几个线程修改同一个Student对象中的age属性。为了保证这几个线程能够工作正常, 我们需要对Student的对象进行同步。下面我们对这个程序进行一点小小的改造,我们通过继承Thread来实现多线程:/**
*
* @author x-spirit
*/
public class ThreadDemo3 extends Thread{
private ThreadLocal<Student> stuLocal = new ThreadLocal<Student>();
public ThreadDemo3(Student stu){
stuLocal.set(stu);
}
public static void main(String[] args) {
Student stu = new Student();
ThreadDemo3 td31 = new ThreadDemo3(stu);
ThreadDemo3 td32 = new ThreadDemo3(stu);
ThreadDemo3 td33 = new ThreadDemo3(stu);
td31.start();
td32.start();
td33.start();
}
@Override
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
Student student = stuLocal.get();
student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge ());
}
}