在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客户端调用代理对象,该客户端同时调用同一代理对象的多个方法。当发生这种情况时,我得到会话实例字段(代理类)以意外方式关闭和打开。
答案 0 :(得分:2)
当多个线程加入proxiedObject时,以下是否安全?
不,除非mo
是volatile
。如果mo
字段为volatile
,那么这将正确跨越内存屏障,并且所有线程都会看到mo
字段的更新。
重要的是要意识到,如果MyObject
不是不可变的,即使mo
为volatile
,也会产生额外的并发问题。
修改强>
感谢@jtahlborn对此的评论。我一直在做一些阅读,现在我很确定volatile
还保护MyObject
免于被部分初始化。
由于constructor instruction reordering possibilities,无法保证MyObject
在线程之间共享引用时已经构造完整。当构造函数完成时,保证构造函数中只有final
个字段被正确初始化。任何其他字段可能已初始化,也可能未初始化,因此在多个线程开始访问之前,您需要在对象上进行同步。
但是,如果mo
字段是易变的,那么“之前发生”保证也可确保MyObject
已完全初始化。在发布volatile
变量之后,不允许编译器对这些指令重新排序。参见: