我想保证我的其中一个中的线程安全Servlet
。SingleThreadModel
已弃用且不保证线程安全。取而代之的是,我可以synchronized
在我的Servlet
.
你是在 Servlet 中保证线程安全的另一种方法吗?
如果是,请解释我该如何实现。
如果不是,我将采用什么设计方法来保证线程安全Servlet
?
我想保证我的其中一个中的线程安全Servlet
。SingleThreadModel
已弃用且不保证线程安全。取而代之的是,我可以synchronized
在我的Servlet
.
你是在 Servlet 中保证线程安全的另一种方法吗?
如果是,请解释我该如何实现。
如果不是,我将采用什么设计方法来保证线程安全Servlet
?
Java Servlet 没有什么特别之处,使其或多或少容易受到线程问题的影响,但是由于 Web 服务器通常具有多线程特性,您在 Java Servlet 中可能遇到的任何线程问题很快就会变得明显。
我之所以这么说,是因为我想强调Java Servlets 并不特殊。您可以轻松编写任何非线程安全的代码。在 Java Servlet 中摆脱它要困难得多。
构建应用程序的一种流行技术是将(逻辑上和物理上)您的代码分成三堆:模型(您的数据)、视图( UI)和控制器——通常缩写为“MVC”。当你这样做时,你认为“视图”和“控制器”是无状态的。也就是说,模型包含程序/用户/事务/任何东西的所有状态,控制器和视图只是根据需要修改该状态并允许该模型在代码中流动。
在 servlet 容器中,Servlet 本身要么是控制器(要么是视图),并且应该是无状态的。这很容易做到:不要使用任何包含任何特定于用户或事务的类成员。任何 Servlet 类成员本身必须是线程安全的(如ConcurrentMap
)或以线程安全的方式使用(例如synchronized
,围绕访问 a 的块HashMap
)。请记住,即使是线程安全的集合(例如ConcurrentMap
)也可以以非线程安全的方式使用,如下所示:
ConcurrentMap cm = ...;
if(!cm.containsKey("foo")) {
cm.put("foo", createFoo());
}
上面的代码不能阻止两个线程调用createFoo
,这可能是一个昂贵的(或破坏性的!)操作。您需要使用同步块来避免两个线程之间的竞争条件。
那么,你把模型放在哪里呢?好吧,您有几种选择。最简单的方法之一是将所有内容保存在用户的session
. 会话是用户特定的结构,可用于所有HttpServletRequest
对象,因此它始终可用于 servlet。不过,这仅在用户实际登录到您的应用程序时才有效。现在让我们假设您确实有用户并且他们有自己的会话。
会话根据发出请求的用户的身份自动与请求相关联。您需要的任何其他数据都应该来自请求本身(可能是来自查询字符串的请求参数)。
您可以将任何您想要的内容放入会话中。描述您的“业务对象”(您用来表示特定应用程序中的概念的东西)的自定义类比Map
包含其他Map
s、Lists
s 等的命名集合的对象更可取。我已经看到了完整的 Web 应用程序标准的 Java 库类,它们是一堆地图查找和魔法列表索引。不要落入那个陷阱:编写自己的类。
用户模型数据的另一种选择是将其存储在某种数据库中。“数据库”有许多选项,从简单的文件存储到关系数据库再到文档/列/索引存储。他们都有自己的长处和短处。但是它们存储数据,您可以将用户模型数据放入数据库。你如何识别用户?可能通过在会话中存储用户 ID。(所以它通常都会回到会话中)。您还可以使用用户的用户名(可从请求中获得)在数据库中查找用户的数据。
在任何情况下,您都不应该在servlet 的类成员中存储有关用户状态(包括工作流等)的任何内容。如果您避免这样做,您就不必担心 servlet 中的线程安全。
另一个问题是共享资源。该问题的解决方案是确保您以线程安全的方式使用这些共享资源。这通常可以通过池化资源来完成,例如数据库的连接池、消息队列、搜索索引等。解决这些问题通常非常特定于共享资源的类型,因此您可能想问一个更具体的问题当你到了那个阶段。