一尘不染

javax.servlet.ServletContext set / getAttribute线程安全吗?

tomcat

必须使用setAttribute()getAttribute(String)中的javax.servlet.ServletContext,我无法通过并发访问找到有关预期行为的任何信息。但是,这些操作很可能由不同的线程调用。

servlet规范3.0的状态:

Servlet可以按名称将对象属性绑定到上下文中。绑定到上下文中的任何属性都可用于属于同一Web应用程序的任何其他servlet。

但是,没有有关这些操作的并发行为的信息。通过查看Apache Tomcat
源代码,可以发现它是作为ConcurrentHashMap实现的,从而使其具有有效的线程安全性。

我的问题是,我应该始终将这些操作视为不是线程安全的,并让应用程序处理同步,还是我缺少一些信息?


阅读 415

收藏
2020-06-16

共1个答案

一尘不染

您可以放心地假设您可以调用getAttribute和setAttribute而不对任何内容进行同步,但是您应该使在那里存储的对象成为线程安全的(最简单的方法是存储不可变的东西)。注释中链接的问题是关于在ServletContext中存储一个可变对象,在这种情况下,使用该对象的线程需要首先获取其锁(已接受的答案对此进行了解释)。

没有明确的要求。《 Java并发实践 》第4.5.1节解释模糊文档中对此进行了介绍:

您将不得不猜测。提高您的猜测质量的一种方法是从将要实施该规范的人员(例如容器或数据库供应商)的角度来解释该规范,而不是仅仅使用它的人员。Servlet总是从容器管理的线程中调用,可以安全地假设,如果有多个这样的线程,则容器知道这一点。Servlet容器使某些为多个Servlet提供服务的对象可用,例如HttpSession或ServletContext。因此,servlet容器应该期望并发地访问这些对象,因为它创建了多个线程并从它们中调用了诸如Servlet.service之类的方法,可以合理地期望它们访问ServletContext。

由于无法想象在这些对象中有用的单线程上下文,因此即使规范没有明确要求它们也必须假定它们已成为线程安全的。此外,如果他们需要客户端锁定,则客户端代码应在什么锁定上同步?该文档没有说,而且似乎很荒谬。规范和官方教程中的示例进一步支持了这种“合理的假设”,这些示例显示了如何访问ServletContext或HttpSession而不使用任何客户端同步。

另一方面,通过setAttribute放置在ServletContext或HttpSession中的对象归Web应用程序所有,而不是Servlet容器。Servlet规范没有建议任何机制来协调对共享属性的并发访问。因此,容器代表Web应用程序存储的属性应该是线程安全的或有效不变的。如果容器所做的全部工作都是代表Web应用程序存储这些属性,则另一种选择是确保从Servlet应用程序代码访问它们时,它们始终受到锁的保护。但是,由于容器可能想要序列化HttpSession中的对象以进行复制或钝化,并且servlet容器可能无法知道您的锁定协议,因此应使它们成为线程安全的。

2020-06-16