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

Ben*_*nni 6 java multithreading tomcat servlets thread-safety

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

servlet规范3.0的状态:

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

但是,没有关于这些操作的并发行为的信息.查看Apache Tomcat 的源代码,可以看出它是作为ConcurrentHashMap实现的,从而使其有效地保证了线程安全.

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

Nat*_*hes 6

你可以放心地假设你可以调用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容器不可能知道你的锁定协议,所以你应该让它们成为线程安全的.