在InvocationHandler中设置代理对象的实例变量

时间:2012-07-19 16:16:42

标签: java multithreading proxy invocationhandler

在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客户端调用代理对象,该客户端同时调用同一代理对象的多个方法。当发生这种情况时,我得到会话实例字段(代理类)以意外方式关闭和打开。

1 个答案:

答案 0 :(得分:2)

  

当多个线程加入proxiedObject时,以下是否安全?

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

重要的是要意识到,如果MyObject不是不可变的,即使movolatile,也会产生额外的并发问题。


修改

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

由于constructor instruction reordering possibilities,无法保证MyObject在线程之间共享引用时已经构造完整。当构造函数完成时,保证构造函数中只有final个字段被正确初始化。任何其他字段可能已初始化,也可能未初始化,因此在多个线程开始访问之前,您需要在对象上进行同步。

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