javax.servlet.ServletContext set / getAttribute是否安全?

时间:2015-07-23 13:15:15

标签: java multithreading tomcat servlets thread-safety

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

servlet specification 3.0州:

  

servlet可以通过名称将对象属性绑定到上下文中。任何   绑定到上下文中的属性可用于任何其他servlet   这是同一个Web应用程序的一部分。

但是,没有关于这些操作的并发行为的信息。查看Apache Tomcat的source code表明它是作为ConcurrentHashMap实现的,从而使其有效地保证了线程安全。

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

1 个答案:

答案 0 :(得分:6)

你可以放心地假设你可以调用getAttribute和setAttribute而不需要同步任何东西,但是你应该让你存储的对象成为线程安全的(最简单的方法是存储不可变的东西)。注释中链接的问题是关于在servletContext中存储可变对象,在这种情况下,使用它的线程需要首先获取其锁(the accepted answer解释)。

没有拼写要求。这将在 Java Concurrency in Practice ,第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容器不可能知道你的锁定协议,所以你应该让它们成为线程安全的。