如何创建线程安全的JSP页面

7

我希望创建一个线程安全的JSP页面。在Servlet中,通过实现SingleThreadModel接口可以实现,但我不知道如何在JSP页面中实现。


2
你不应该这样做。这意味着你的设计完全有缺陷。如果在真实的商业世界中这样做,你将被解雇。请参阅Servlets和线程安全以及如何避免在JSP中使用Java代码 - BalusC
6个回答

9
理论上,可以通过isThreadSafe页面指令属性将JSP页面标识为线程安全。设置false的值,将使容器同步访问页面级别的对象(而不是会话和应用程序范围的对象或任何其他类型的对象)。显然,开发人员仍然有责任确保对线程不安全的代码区域进行同步访问。
此外,在Servlet规范发布2.4版中,SingleThreadModel接口也已被弃用。SingleThreadModel接口也用于实现JSP中所谓的线程安全性-生成的servlet类将为使用线程安全属性的JSP实现SingleThreadModel。规范本身概述了接口为什么被弃用:
引用如下: SRV.2.2.1关于单线程模型的注释
使用SingleThreadModel接口可保证每个servlet实例的服务方法中一次只有一个线程执行。重要的是要注意,该保证仅适用于每个servlet实例,因为容器可能选择对这些对象进行池化。多个servlet实例同时访问的对象,例如HttpSession的实例,可能随时可用于多个servlet,包括实现SingleThreadModel的servlet。
建议开发人员采取其他方法来解决这些问题,而不是实现此接口,例如避免使用实例变量或同步访问访问这些资源的代码块。SingleThreadModel接口在此版本的规范中已被弃用。

注意:SingleThreadModel自Servlet 2.4版本起已被弃用,并将在Servlet 6.0中删除。此更改使JSP的isThreadSafe指令无效。 - Joakim Erdfelt

5

首先是简短的答案 <%@page isThreadSafe="false" %>

更详细的回答是不要这样做。

你需要非常清楚你的目标。使用SingleThreadModel并没有使得Servlet真正具备线程安全性,而是设置了只有一个线程可以进入你的Servlet。我猜你这么做是因为Servlet代码不是线程安全的,如果多个线程同时访问代码会发生不好的事情。

这对我意味着你在Servlet代码中有类似这样的内容:

   doGet(/*etc/*){

       // ... stuff

           someExistingUnsafeClass.doSomething();

       // .. more stuff

   }

毕竟,你的 servlet 代码本身肯定不会出现线程不安全的问题,对吧?你一定会修复它,是吗?所以肯定是一些遗留代码存在线程不安全的问题?

如果是这种情况,在你的 JSP 中需要使用现有的遗留代码,在其中某个地方会调用不安全的内容:

<%
         someExistingUnsafeClass.doSomething();
%>

因此,您只需要保护这个不安全的调用:

<%
  synchronized(this){
         someExistingUnsafeClass.doSomething();

  };
%>

允许大部分JSP以正确的线程运行将会提高性能。

我还应该说,如果您将应用程序构建为MVC,则所有不安全的代码都是从控制器调用的,视图(即JSP)永远不需要不安全。


3

如果您的JSP页面没有任何状态信息(即没有实例变量可以在不同请求之间更改),那么它们是线程安全的。


1
谈论 JSP 的线程安全是错误的 - JSP 是一种视图技术,它只显示结果 - 它不进行任何处理。(它可以进行处理,但不应该)
通过在 servlet 中没有私有字段来实现 servlet 的线程安全性 - servlet 实例对整个容器来说是一个实例,每个请求都是调用 service(..) 方法的新线程。
您应该明确指定您在这种情况下所指的“线程安全” - 即您希望发生什么失败。

抱歉,那不是正确的。JSP 可以(虽然不应该)包含任意的 Java 代码,这可能不是线程安全的。 - djna

1
在JSP中,只需在脚本中使用变量,您就可以放心它们是线程安全的,因为它们将被翻译成service()中的局部变量。

0

不需要。

JSP基本上是一个servlet中的单个方法。正如您可能已经知道的那样,方法是线程安全的,也就是说,同时调用同一对象的同一方法的两个线程将在各自的堆栈中执行。

因此,您实际上不需要创建一个线程安全的JSP,因为它已经是线程安全的。

如果您在JSP中声明变量a,则没有其他请求可以看到该变量。

您必须注意的是,放入会话或上下文中的对象可能会被多个线程同时访问,或者几乎不是线程安全的代码。然后,您必须同步或注意这些对象!而不是JSP页面本身。


@djna: +1 是的,这就是我想说的。JSP 本身不需要同步,但你在其中使用的对象需要同步。我稍微修改了一下编辑以强调这一点。 - OscarRyz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接