Java 线程局部变量的对象引用能否安全地共享给其他线程?
考虑一个场景:Java 线程局部变量的对象引用能否安全地共享给其他线程?,java,multithreading,spring,session,Java,Multithreading,Spring,Session,考虑一个场景: MySessionObject object = Session.getObject(); //then object is passed to Runnable task. private class MyTask implements Runnable { private final MySessionObject object; public SaveVisitorTask(MySessionObject object) { this
MySessionObject object = Session.getObject();
//then object is passed to Runnable task.
private class MyTask implements Runnable {
private final MySessionObject object;
public SaveVisitorTask(MySessionObject object) {
this.object = object;
}
@Override
public void run() {
MyDao dao = new MyDao();
MySessionObject savedObject = dao.save(object);
this.object.setId(savedObject.getId());
}
}
说明:
原子操作要么完成,要么根本不完成。其他线程将无法看到“正在进行”的操作。它将永远不会在部分完成状态下查看。语句
this.object.setId(savedObject.getId())代码>实际上会影响原始对象。因为对象
不是从其他线程的线程本地检索的,而是直接传递给其他线程
如果调用Session.getObject()代码>在第二个线程中,然后它将返回对象的特定于线程的副本
显然,线程局部变量(会话)不能共享给
线程,但它所包含的引用呢
ThreadLocal
变量放在场景后面的Thread
类中的一个特殊映射中,该映射维护设置的值。map中条目的键是调用线程本身,值是通过ThreadLocal
的“set”方法设置的值
public class Thread implements Runnable {
..................
..................
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
}
现在,它们结束在这里的原因是,在某个点上,一段代码(在方法内部)在Threadlocal上运行,该代码称为“set”,它在threadlocals映射中创建了一个条目,其中key作为线程,value作为对象集
public class ThreadLocal<T> {
.........
.........
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
}
公共类ThreadLocal{
.........
.........
/**
*设置此线程局部变量的当前线程副本
*到指定的值。大多数子类将不需要
*重写此方法,仅依赖{@link#initialValue}
*方法来设置线程局部变量的值。
*
*@param value要存储在当前线程的
*这个线程是本地的。
*/
公共无效集(T值){
Thread t=Thread.currentThread();
ThreadLocalMap=getMap(t);
if(map!=null)
map.set(这个,值);
其他的
createMap(t,值);
}
}
因此,只要设置的变量没有从线程方法堆栈中转义,它对每个线程都是唯一的,因此是线程安全的。但是,如果它指向某些共享变量,例如类的实例变量,则多个线程有可能指向threadlocal映射中的同一对象。在这种情况下,它肯定不是线程安全的。此外,的文件中也提到了这一点:
每个线程都包含对其本地线程副本的隐式引用
变量,只要线程处于活动状态且ThreadLocal实例
交通便利;线程消失后,其线程本地实例的所有副本都将接受垃圾收集(除非另有说明)
存在对这些副本的引用)
您完全正确,但问题不在于使用什么?
,而在于是否有效?
和如何有效?
:)根据定义,最终字段在构建对象后不会更改。如果您真正的意思是希望字段设置一次。所以我认为它不起作用,因为你有一个用final关键字声明的对象的setter。任何对象都可以在线程之间共享。您所要做的就是将对象的引用放在多个线程可以看到它的位置。但是,在ThreadLocal
对象中存储对共享对象的引用不是有点违背了ThreadLocal
的目的吗?这肯定违反了最不令人惊讶的原则。