该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-04-08
spiritfrog 写道 感觉这样解释反而变得有些麻烦了,直接看下源码倒简单些。
横向的实际上是,同一个线程a中,三个threadlocal对象保存x,y,z,实际上在a线程的map中,以threadlocal对象为key保存x,y,z 纵向的,说的是不同线程的情况,分别用threadlocal保存对象x,结果每个线程的map都保存了x。实际上这个x也是不安全的,因为三个线程都能访问它,如果能修改的话。 楼上的,对纵向的理解是不对的。 变量x对于线程而言是安全的,而非不安全的。如果X是java的原生类型,则在每个线程中存在的是X的值副本;如果X是对象类型,那么每个线程中的对象引用也是不同的,因为对方法中的X的值改变,只影响当前X的引用(或者说指针的指向),不会影响其他线程的副本值,这也是所谓副本的含义。你可以做个实验。 |
|
返回顶楼 | |
发表时间:2008-04-08
linliangyi2007 写道 楼上的,对纵向的理解是不对的。 变量x对于线程而言是安全的,而非不安全的。如果X是java的原生类型,则在每个线程中存在的是X的值副本;如果X是对象类型,那么每个线程中的对象引用也是不同的,因为对方法中的X的值改变,只影响当前X的引用(或者说指针的指向),不会影响其他线程的副本值,这也是所谓副本的含义。你可以做个实验。 当x是对象类型时,X必须是逃逸型引用,而不能是非逃逸型引用,即X是通过在本地方法中产生的,这就是所谓local的含义。如果X是非逃逸型的,则仍然有同步问题。 比如: class A{ private Object v; public A(){ v=new Object(); } public ThreadLocal method1(){ ThreadLocal local=new ThreadLocal(); local.set(v); //对象v是非逃逸型引用,这儿的local所引用的对像是非同步安全的 return local; } public ThreadLocal method2(){ ThreadLocal local = new ThreadLocal(); local.set(new Object()); //这儿的值是逃逸类型的,因此local是同步安全的 return local; } public void methodUseLocal(){ ThreadLocal local1=method1(); Object tempv1=local1.get(); //这儿的tempv1其实就是this.v,因此是非线程安全的 //... ThreadLocal local2=method2(); Object tempv2=local2.get(); //这儿的tempv2是线程安全的,是和当前线程绑定的变量 //... } } |
|
返回顶楼 | |
发表时间:2008-04-08
rehte 写道 linliangyi2007 写道 楼上的,对纵向的理解是不对的。 变量x对于线程而言是安全的,而非不安全的。如果X是java的原生类型,则在每个线程中存在的是X的值副本;如果X是对象类型,那么每个线程中的对象引用也是不同的,因为对方法中的X的值改变,只影响当前X的引用(或者说指针的指向),不会影响其他线程的副本值,这也是所谓副本的含义。你可以做个实验。 当x是对象类型时,X必须是逃逸型引用,而不能是非逃逸型引用,即X是通过在本地方法中产生的,这就是所谓local的含义。如果X是非逃逸型的,则仍然有同步问题。 比如: class A{ private Object v; public A(){ v=new Object(); } public ThreadLocal method1(){ ThreadLocal local=new ThreadLocal(); local.set(v); //对象v是非逃逸型引用,这儿的local所引用的对像是非同步安全的 return local; } public ThreadLocal method2(){ ThreadLocal local = new ThreadLocal(); local.set(new Object()); //这儿的值是逃逸类型的,因此local是同步安全的 return local; } public void methodUseLocal(){ ThreadLocal local1=method1(); Object tempv1=local1.get(); //这儿的tempv1其实就是this.v,因此是非线程安全的 //... ThreadLocal local2=method2(); Object tempv2=local2.get(); //这儿的tempv2是线程安全的,是和当前线程绑定的变量 //... } } 楼上提醒的是。实际上,我们对于一个方法是用ThreadLocal来对本地变量进行副本的时候,大多指的是方法内部变量(请看我的示意图,X是方法内部的local varible)。要对类变量进行共享的话,不是ThreadLocal设计的目的。 但确实存在这样的问题,值得大家注意。 |
|
返回顶楼 | |
发表时间:2008-04-11
linliangyi2007 写道 rehte 写道 linliangyi2007 写道 楼上的,对纵向的理解是不对的。 变量x对于线程而言是安全的,而非不安全的。如果X是java的原生类型,则在每个线程中存在的是X的值副本;如果X是对象类型,那么每个线程中的对象引用也是不同的,因为对方法中的X的值改变,只影响当前X的引用(或者说指针的指向),不会影响其他线程的副本值,这也是所谓副本的含义。你可以做个实验。 当x是对象类型时,X必须是逃逸型引用,而不能是非逃逸型引用,即X是通过在本地方法中产生的,这就是所谓local的含义。如果X是非逃逸型的,则仍然有同步问题。 比如: class A{ private Object v; public A(){ v=new Object(); } public ThreadLocal method1(){ ThreadLocal local=new ThreadLocal(); local.set(v); //对象v是非逃逸型引用,这儿的local所引用的对像是非同步安全的 return local; } public ThreadLocal method2(){ ThreadLocal local = new ThreadLocal(); local.set(new Object()); //这儿的值是逃逸类型的,因此local是同步安全的 return local; } public void methodUseLocal(){ ThreadLocal local1=method1(); Object tempv1=local1.get(); //这儿的tempv1其实就是this.v,因此是非线程安全的 //... ThreadLocal local2=method2(); Object tempv2=local2.get(); //这儿的tempv2是线程安全的,是和当前线程绑定的变量 //... } } 楼上提醒的是。实际上,我们对于一个方法是用ThreadLocal来对本地变量进行副本的时候,大多指的是方法内部变量(请看我的示意图,X是方法内部的local varible)。要对类变量进行共享的话,不是ThreadLocal设计的目的。 但确实存在这样的问题,值得大家注意。 方法内部变量 还用担心线程安全问题吗? 当然是类变量才需要担心了。 不太明白那个逃逸型非逃逸型是什么意思, 例子里面那个逃逸类型,及方法内部变量,没有线程安全问题, 非逃逸类型,用了ThreadLocal,自然也就安全了。 |
|
返回顶楼 | |
发表时间:2008-04-11
xieke 写道 linliangyi2007 写道 rehte 写道 linliangyi2007 写道 楼上的,对纵向的理解是不对的。 变量x对于线程而言是安全的,而非不安全的。如果X是java的原生类型,则在每个线程中存在的是X的值副本;如果X是对象类型,那么每个线程中的对象引用也是不同的,因为对方法中的X的值改变,只影响当前X的引用(或者说指针的指向),不会影响其他线程的副本值,这也是所谓副本的含义。你可以做个实验。 当x是对象类型时,X必须是逃逸型引用,而不能是非逃逸型引用,即X是通过在本地方法中产生的,这就是所谓local的含义。如果X是非逃逸型的,则仍然有同步问题。 比如: class A{ private Object v; public A(){ v=new Object(); } public ThreadLocal method1(){ ThreadLocal local=new ThreadLocal(); local.set(v); //对象v是非逃逸型引用,这儿的local所引用的对像是非同步安全的 return local; } public ThreadLocal method2(){ ThreadLocal local = new ThreadLocal(); local.set(new Object()); //这儿的值是逃逸类型的,因此local是同步安全的 return local; } public void methodUseLocal(){ ThreadLocal local1=method1(); Object tempv1=local1.get(); //这儿的tempv1其实就是this.v,因此是非线程安全的 //... ThreadLocal local2=method2(); Object tempv2=local2.get(); //这儿的tempv2是线程安全的,是和当前线程绑定的变量 //... } } 楼上提醒的是。实际上,我们对于一个方法是用ThreadLocal来对本地变量进行副本的时候,大多指的是方法内部变量(请看我的示意图,X是方法内部的local varible)。要对类变量进行共享的话,不是ThreadLocal设计的目的。 但确实存在这样的问题,值得大家注意。 方法内部变量 还用担心线程安全问题吗? 当然是类变量才需要担心了。 不太明白那个逃逸型非逃逸型是什么意思, 例子里面那个逃逸类型,及方法内部变量,没有线程安全问题, 非逃逸类型,用了ThreadLocal,自然也就安全了。 说的自己都晕了,一句话,ThreadLocal不是专门为线程安全而设计的,更多是为了变量的共享。 |
|
返回顶楼 | |