可以将来自线程局部变量的对象引用共享给其他线程吗?

时间:2015-10-20 03:12:40

标签: 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.object = object;
    }

    @Override
    public void run() {
        MyDao dao = new MyDao();
        MySessionObject savedObject = dao.save(object);
        this.object.setId(savedObject.getId());
    }

}

说明

  1. 从会话中恢复的对象,例如线程局部变量。
  2. 然后将其传递给Runnable任务,并以异步方式保存
  3. 然后将新的id从保存的对象设置为来自线程局部变量的对象。
  4. 问题很简单 - 代码线程安全吗?很明显,线程局部变量(session)不能 被共享到线程,但它拥有的引用怎么样?声明this.object.setId(savedObject.getId());是否会影响原始对象?

    P.S。如果此代码不是线程安全的(我个人认为)可以解释为什么?

3 个答案:

答案 0 :(得分:0)

查看Java Atomic Variables

原子操作将完成或根本不完成。其他线程将无法看到“正在进行”的操作。它永远不会被视为部分完整的状态。

答案 1 :(得分:0)

语句this.object.setId(savedObject.getId());实际上影响了原始对象。因为在其他线程中没有从本地线程检索object,而是直接将其传递给其他线程。

如果你在第二个帖子中调用Session.getObject();,那么它将返回一个特定于线程的对象副本。

答案 2 :(得分:0)

  很明显,线程局部变量(session)无法共享   线程,但它拥有的引用呢?

ThreadLocal变量放在场景后面的Thread类中的特殊地图中,此地图维护设置的值。 map中条目的键是调用线程本身,value是由" set"设置的值。 ThreadLocal的方法。

public class Thread implements Runnable {

..................
..................
/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;


}

现在他们在这里结束的原因是因为在某些时候,一段代码(在一个方法内)运行了一个名为" set"在Threadlocal上创建一个条目到threadlocals映射,其中key作为线程,值作为对象集。

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映射中的同一个对象。在这种情况下 - 它绝对不是线程安全的。 Threadlocal的文档也提到了这一点:

  

每个线程都拥有对其本地线程副本的隐式引用   只要线程是活动的并且是ThreadLocal实例的变量   可以访问;一个线程消失后,它的所有线程局部实例副本都会被垃圾收集(除非其他   存在对这些副本的引用。)