背景
Apache Action类不是线程安全的。然而,这只是在实现了一个基类之后才实现的,系统中的所有其他类都依赖于该基类。基类使用许多实例变量:
private HttpServletRequest request;
private ArrayList inputParams = new ArrayList();
private Connection connection;
private String outputParameter;
private boolean exportEnabled;
幸运的是,这些变量的所有使用都是通过访问器方法完成的。例如:
public boolean getExportEnabled() {
return this.exportEnabled;
}
public void setExportEnabled( boolean exportEnabled ) {
this.exportEnabled = exportEnabled;
}
问题
基类在多线程 Servlet 环境中运行。
解决方案#1
为了解决这个问题,我正在考虑使用键控到会话的HashMap 。但是,这需要重写所有方法和相关代码:
private static HashMap sessionVariables = new HashMap();
public boolean getExportEnabled( HttpSession session ) {
return getSessionVariables().get( session.getId() + '.exportEnabled' );
}
public void setExportEnabled( boolean exportEnabled, HttpSession session ) {
getSessionVariables().put( session.getId() + '.exportEnabled', exportEnabled );
}
这是很多工作,并且可能会引入错误。
解决方案#2
可以将基类更改为“空”类。这个空类只有一个方法:
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response )
throws Exception {
// Instantiate "this" and forward the request?
}
但它必须知道要实例化的适当基类,或者可能实例化自身的新版本来处理调用。
更新#1
我相信 Struts 架构可以做到以下几点:
- 创建 Action 子类的实例。
- 为每个请求重复使用相同的实例。
- 接收新连接时获取线程(从线程池中)。
execute
从线程调用Action 子类。- 使用不同的线程处理多个新连接。
相同的execute
方法将在对象的相同实例上调用,导致不安全的行为,因为子类具有实例变量。
更新#2
以下解决方案似乎可以解决问题:
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response ) throws Exception {
((MyClass)clone()).executeClone( mapping, form, request, response );
}
public ActionForward executeClone(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response ) throws Exception {
// Former "execute" method code goes here.
// ...
}
原来的execute
方法被重命名为executeClone
. 新的execute
实现创建了当前类的克隆并随后调用executeClone
. 这种微创技术避免了引入新的错误,同时使类线程安全。
问题
什么是使代码线程安全同时最小化引入错误的风险的最可靠方法?
谢谢!