0

在 Proxy 对象(实现的对象java.lang.reflect.InvocationHandler)中,我试图在代理对象中设置一个实例变量。

如下所示:

public class ServiceProxy implements InvocationHandler {

    private final Object proxiedObject;

    private ServiceProxy(final Object object) {
        this.proxiedObject = object;
    }

    public static Object newInstance(final Object object) {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new ServiceProxy(object));
    }


    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {

        Object result = null;
        MyObject mo = new MyObject();

        // Is the following safe when the proxiedObject is being acceessed by multiple threads?
        final Field sessionField = this.proxiedObject.getClass().getSuperclass().getDeclaredField("mo");
        sessionField.setAccessible(true);
        sessionField.set(this.object, mo);


        result = method.invoke(this.proxiedObject, args);


        return result;
    }
}

这安全吗?

编辑

实际代码:

Object result = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession()

// Is the following save when the proxiedObject is being acceessed by multiple threads?
final Field sessionField = this.proxiedObject.getClass().getSuperclass().getDeclaredField("session");
sessionField.setAccessible(true);
sessionField.set(this.object, session);

result = method.invoke(this.proxiedObject, args);
return result;

Edit2 : 代理对象是从 GWT 客户端调用的,该客户端同时调用同一代理对象的多个方法。发生这种情况时,我让会话实例字段(代理类)以意想不到的方式关闭和打开。

4

1 回答 1

2

当 proxiedObject 被多个线程访问时,以下内容是否安全?

不,除非movolatile。如果该mo字段是,volatile那么这将正确跨越内存屏障,并且mo所有线程都将看到对该字段的更新。

重要的是要认识到,如果MyObject不是不可变的,即使mo是也会导致额外的并发问题volatile


编辑:

感谢@jtahlborn 对此的评论。我一直在做一些阅读,现在我很确定这volatile也会保护不MyObject部分初始化。

由于构造函数指令重新排序的可能性,不能保证MyObject当其引用在线程之间共享时已经构造完成。当构造函数完成时,只有final构造函数中的字段才能保证正确初始化。任何其他字段可能已初始化,也可能未初始化,因此您需要在多个线程开始访问它之前对对象进行同步。

但是,如果该mo字段是 volatile 的,那么“发生在之前”的保证也可以确保MyObject已完全初始化。不允许编译器在发布volatile变量后重新排序这些指令。看:

于 2012-07-19T16:23:12.400 回答