精华帖 (8) :: 良好帖 (15) :: 新手帖 (9) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-05-31
klyuan 写道 ThreadLocal与synchronized
这个类有一个Student的私有变量,在run方法中,它随机产生一个整数。然后设置到student变量中,从student中读取设置后的值。然后睡眠5秒钟,最后再次读student的age值。 public class ThreadDemo implements Runnable{ [color=red]Student student = new Student();[/color] public static void main(String[] agrs) { ThreadDemo td = new ThreadDemo(); Thread t1 = new Thread(td,"a"); Thread t2 = new Thread(td,"b"); t1.start(); t2.start(); } /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { accessStudent(); } public void accessStudent() { String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); // System.out.println("first read age is:"+this.student.getAge()); Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); this.student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge()); } } 注意:这里的this.student.setAge(age); 我们把第一个例子用ThreadLocal来实现,但是我们需要些许改变。 Student并不是一个私有变量了,而是需要封装在一个ThreadLocal对象中去。调用ThreadLocal的set方法,ThreadLocal会为每一个线程都保持一份Student变量的副本。所以对student的读取操作都是通过ThreadLocal来进行的。 protected Student getStudent() { Student student = (Student)studentLocal.get(); if(student == null) { student = new Student(); studentLocal.set(student); } return student; } protected void setStudent(Student student) { studentLocal.set(student); } accessStudent()方法需要做一些改变。通过调用getStudent()方法来获得当前线程的Student变量,如果当前线程不存在一个Student变量,getStudent方法会创建一个新的Student变量,并设置在当前线程中。 Student student = getStudent(); student.setAge(age); accessStudent()方法中无需要任何同步代码。 完整的代码清单如下: TreadLocalDemo.java public class TreadLocalDemo implements Runnable { private final static ThreadLocal studentLocal = new ThreadLocal(); public static void main(String[] agrs) { TreadLocalDemo td = new TreadLocalDemo(); Thread t1 = new Thread(td,"a"); Thread t2 = new Thread(td,"b"); t1.start(); t2.start(); } /* (non-Javadoc) * @see java.lang.Runnable#run() */ 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 = getStudent(); 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()); } protected Student getStudent() { Student student = (Student)studentLocal.get(); if(student == null) { student = new Student(); studentLocal.set(student); } return student; } protected void setStudent(Student student) { studentLocal.set(student); } } Student student = getStudent(); student.setAge(age); 可见,使用ThreadLocal后,我们不需要任何同步代码,却能够保证我们线程间数据的安全。 而且,ThreadLocal的使用也非常的简单。 我们仅仅需要使用它提供的两个方法 void set(Object obj) 设置当前线程的变量的副本的值。 Object get() 返回当前线程的变量副本 由此可见,ThreadLocal通过一个Map来为每个线程都持有一个变量副本。这个map以当前线程为key。与synchronized相比,ThreadLocal是以空间换时间的策略来实现多线程程序。 Synchronized还是ThreadLocal? ThreadLocal以空间换取时间,提供了一种非常简便的多线程实现方式。因为多个线程并发访问无需进行等…………………… 注意引用中标记了红色的地方,也就是使用ThreadLocal改造前后Student student的作用范围的变化,如果使用这中方式来解决并发的问题,我想也完全没有必要引入ThreadLocal了,直接在accessStudent方法中这样处理就OK了 Student student = new Student();: public void accessStudent(){ //synchronized(this){ String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); // System.out.println("first read age is:"+this.student.getAge()); Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); Student student = new Student(); student.setAge(age); 相信这样每个线程,读出来的数据也不可能会有交叉的问题. |
|
返回顶楼 | |
发表时间:2007-05-31
因为引用的东西比较长,同时又不能在代码块中“着色”来强调我需要突出的问题,从我上面的回复不知道这里的各位是否明白了我的意图:其实LZ在解释synchornized和ThreadLocal的过程中改变了
accessStudent()中的student,正是这一点的改变,才使得楼主感觉到了ThreadLocal可以做到同步…………,如果是这种情况下也能同步的话,我想楼主是对的,但根据楼主的逻辑,下面的处理方法恐怕测试通不过: public class ThreadDemo implements Runnable { private ThreadLocal local = new ThreadLocal(); private Student student = getStudent(); ………………………… ………………………………… public void accessStudent(){ //synchronized(this){ String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); // System.out.println("first read age is:"+this.student.getAge()); Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); //Student student = new Student(); student.setAge(age); System.out.println("thread "+currentThreadName+ " first read age is:"+student.getAge()); try { Thread.sleep(5000); } 上面的代码中accessStudent使用的实例student来自ThreadDemo,这也是和楼主使用synchronized的时候是相同“地位”的, |
|
返回顶楼 | |
发表时间:2007-05-31
嗯。。ThreadLocal根本不能解决共享资源访问的问题,我想有很多人误用了synchronized,原本不需要用到同步,用ThreadLocal就能解决问题了.却用同步这种极其降低性能的方法。。所以能够ThreadLocal来代替Synchronized的地方,最好用ThreadLocal,真正只能用Synchronized的地方,ThreadLocal也只能干蹬眼
|
|
返回顶楼 | |
发表时间:2007-06-28
俺觉得.楼主的主要意思就是如何避免线程之间的冲突,说明了两种情况而已
|
|
返回顶楼 | |
发表时间:2007-07-06
我认为ThreadLocal是在多线程环境下,为各线程的资源(存放在threadLocals中)提供了一个管理方法。
目的并不是为了解决多线程环境中的并发访问控制。 |
|
返回顶楼 | |
发表时间:2007-07-06
常人都喜欢纵向的钻研问题!
而不善于横向的分析,比较问题! 所以就被有人投诉了! 当然,本文的某些地方的确不够严谨! |
|
返回顶楼 | |
发表时间:2007-07-06
我想现在处理并发的方式已经简单很多了.
JDK5提供了一组concurrent的对象给我们访问,这可是大师Doug Lea的作品 jdk6更加完善了这一package. 大家可以看下java.util.concurrent |
|
返回顶楼 | |
发表时间:2007-07-29
貌似threadloacl跟线程安全没什么关系,理解保证得到的对象是单例
网上的一个简单实现public class ThreadLocal { private Map values = Collections.synchronizedMap(new HashMap()); public Object get() { Thread curThread = Thread.currentThread(); Object o = values.get(curThread); if (o == null && !values.containsKey(curThread)) { o = initialValue(); values.put(curThread, o); } return o; } public void set(Object newValue) { values.put(Thread.currentThread(), newValue); } public Object initialValue() { return null; } } |
|
返回顶楼 | |
发表时间:2007-08-06
看了一天的ThreadLocal,看到lz这篇才感觉对ThreadLocal有了一个深入的理解,通过两个比较,能更深入的了解ThreadLocal。看这篇文章之前也看其他的介绍ThreadLocal的文章,基本看不懂,一头雾水。谢谢LZ!
|
|
返回顶楼 | |
发表时间:2007-10-15
有2个小宝宝,要抢喝奶,于是“同步”是这样来实现的,给宝宝一个先后顺序,一个一个的喝,ThreadLocal是另外一种方式,就是有几个宝宝就几个奶妈,于是一个宝宝配一个奶妈,特别是杏仁茶都磨得出的那种奶妈,这两种方式都能让宝宝不闹,
|
|
返回顶楼 | |