Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程局部变量的对象引用能否安全地共享给其他线程?_Java_Multithreading_Spring_Session - Fatal编程技术网

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());
    }

}
说明:

  • 从会话检索的对象,例如线程局部变量
  • 然后将其传递给可运行任务,并在其中异步持久化
  • 然后从保存的对象到线程局部变量中的对象设置新id
  • 问题很简单——代码是线程安全的吗?显然,线程局部变量(session)不能 可以共享给线程,但是它所包含的引用呢?语句是否执行this.object.setId(savedObject.getId())是否影响原始对象

    p.S.如果此代码不是线程安全的(我个人认为是),有人能解释一下原因吗

    看看Java


    原子操作要么完成,要么根本不完成。其他线程将无法看到“正在进行”的操作。它将永远不会在部分完成状态下查看。

    语句
    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
    的目的吗?这肯定违反了最不令人惊讶的原则。