java - 将类从线程不安全迁移到线程安全

标签 java thread-safety struts

背景

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锁定 session 。但是,这需要重写所有方法和相关代码:

  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 架构具有以下功能:

  1. 创建 Action 子类的实例。
  2. 为每个请求重复使用同一个实例。
  3. 接收新连接时获取线程(从线程池)。
  4. 从线程中调用 Action 子类的 execute
  5. 使用不同的线程处理多个新连接。

将在对象的同一实例上调用相同的 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。这种微创技术避免了引入新的错误,同时使类线程安全。

问题

什么是最可靠的方法来使代码线程安全,同时最大限度地减少引入错误的风险?

谢谢!

最佳答案

解决方案 #1 很危险,因为它假设 session 是线程安全的,但事实并非如此。有人可能会在同一个 session 中同时发出两个请求。

通过使基类实现Cloneable,可以轻松实现解决方案#2。然后它可以克隆自身,设置克隆的实例变量,然后调用 super.execute()。如果您认为更改设计以使基类具有适当的线程安全性太难,这可能是一个简单的方法。

关于java - 将类从线程不安全迁移到线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11068511/

相关文章:

java - String replaceAll(,) 方法 Java 的不区分大小写的变量

java - servlet的service方法中的HashMap

java - 如何克服 JFreeChart 问题?

java - 未找到 web.xml。模拟struts测试用例

java - 前瞻性思维 : Library Dependency handling in the workplace

java - OnTouchEvent 与主类位于不同的类中

java - 方法需要从字符串数组返回一个值

Spring和Tika集成: is my approach thread-safe?

java - 我不明白为什么java中的不可变对象(immutable对象)本质上总是线程安全的

java - JSON 数据未在 JSP 中显示