SingleThreadModel 已被弃用并且不保证线程安全,保证 Servlet 中线程安全的最佳 soluation/design 方法是什么?
SingleThreadModel is deprecated and does not guarantee thread safety, what is the best soluation/design approch to guarantee thread safety in Servlet?
我想在我的 Servlet
之一中保证线程安全。 SingleThreadModel
已弃用,不保证线程安全。相反,我可以在我的 Servlet
.
中使用 synchronized
块
有没有另一种方法来保证 Servlet 中的线程安全?
如果是,请说明如何实现。
如果没有,我在Servlet
中保证线程安全的设计方法是什么?
Java Servlet 并没有什么特别之处使它或多或少容易受到线程问题的影响,但是您在 Java Servlet 中可能遇到的任何线程问题很快就会变得明显,因为Web 服务器的多线程特性 一般。
我说以上只是因为我想强调 Java Servlet 并不特殊 的观点。您可以轻松编写任何非线程安全的代码。在 Java Servlet 中很难摆脱它。
构建应用程序的一种流行技术是(在逻辑上和物理上)将您的代码分成三堆:m模型(您的数据),v iew (UI),以及 controller——通常缩写为 "MVC"。当您这样做时,您认为 "view" 和 "controller" 是 stateless。也就是说,模型包含 program/user/transaction/whatever 的所有状态,控制器和视图只需根据需要修改该状态并允许该模型在代码中流动。
在servlet 容器中,Servlet 本身要么是控制器(要么是视图),应该是无状态的。这 非常 容易做到:只要不使用任何 class 包含任何特定于用户或交易的成员即可。任何 Servlet class 成员本身必须是线程安全的(如 ConcurrentMap
)或以线程安全的方式使用(例如 synchronized
阻止访问 HashMap
)。请记住,即使是线程安全的集合(例如 ConcurrentMap
)也可以以非线程安全的方式使用,如下所示:
ConcurrentMap cm = ...;
if(!cm.containsKey("foo")) {
cm.put("foo", createFoo());
}
上面的代码不能阻止两个线程调用 createFoo
,这可能是一个昂贵的(或破坏性的!)操作。您需要使用同步块来避免两个线程之间的 race condition。
那么,你把模型放在哪里?好吧,您有多种选择。最简单的方法之一是将所有内容保存在用户的 session
中。会话是一种特定于用户的结构,可用于所有 HttpServletRequest
对象,因此它始终可用于 servlet。不过,这仅在用户实际登录到您的应用程序时才有效。现在让我们假设您确实有用户并且他们有自己的会话。
会话会根据发出请求的用户的身份自动与请求相关联。您需要的任何其他数据都应该来自请求本身(可能是来自 query string 的请求 参数 )。
您可以将任何您想要的内容放入会话中。描述您的 "business objects" 的自定义 classes(您在特定应用程序中用来表示概念的东西)优于包含其他 Map
s 命名集合的 Map
对象, Lists
s 等。我见过完全使用标准 Java 库 classes 构建的 Web 应用程序,它们是一堆地图查找和魔法列表索引。不要落入那个陷阱:编写自己的 classes.
用户模型数据的另一种选择是将其存储在某种数据库中。 "database" 有很多选择,从简单的文件存储到关系数据库再到 document/column/index 存储。他们都有自己的长处和短处。但是它们存储数据,您可以将用户模型数据放入数据库中。你如何识别用户?可能通过在会话中存储用户 ID。 (所以它通常都回到会话)。您还可以使用用户的用户名(可从请求中获得)在数据库中查找用户的数据。
无论如何,您应该不在 servlet 的 class 成员中存储任何关于用户状态(包括工作流等)的信息。如果你避免这样做,你就不会担心 servlet 中的线程安全。
另一个问题是共享资源。该问题的解决方案是确保以线程安全的方式使用这些共享资源。这通常可以通过池化资源来完成,例如数据库的连接池、消息队列、搜索索引等。解决这些问题通常非常特定于共享资源的类型,因此您可能想问一个更具体的问题当你到达那个阶段时。
我想在我的 Servlet
之一中保证线程安全。 SingleThreadModel
已弃用,不保证线程安全。相反,我可以在我的 Servlet
.
synchronized
块
有没有另一种方法来保证 Servlet 中的线程安全?
如果是,请说明如何实现。
如果没有,我在Servlet
中保证线程安全的设计方法是什么?
Java Servlet 并没有什么特别之处使它或多或少容易受到线程问题的影响,但是您在 Java Servlet 中可能遇到的任何线程问题很快就会变得明显,因为Web 服务器的多线程特性 一般。
我说以上只是因为我想强调 Java Servlet 并不特殊 的观点。您可以轻松编写任何非线程安全的代码。在 Java Servlet 中很难摆脱它。
构建应用程序的一种流行技术是(在逻辑上和物理上)将您的代码分成三堆:m模型(您的数据),v iew (UI),以及 controller——通常缩写为 "MVC"。当您这样做时,您认为 "view" 和 "controller" 是 stateless。也就是说,模型包含 program/user/transaction/whatever 的所有状态,控制器和视图只需根据需要修改该状态并允许该模型在代码中流动。
在servlet 容器中,Servlet 本身要么是控制器(要么是视图),应该是无状态的。这 非常 容易做到:只要不使用任何 class 包含任何特定于用户或交易的成员即可。任何 Servlet class 成员本身必须是线程安全的(如 ConcurrentMap
)或以线程安全的方式使用(例如 synchronized
阻止访问 HashMap
)。请记住,即使是线程安全的集合(例如 ConcurrentMap
)也可以以非线程安全的方式使用,如下所示:
ConcurrentMap cm = ...;
if(!cm.containsKey("foo")) {
cm.put("foo", createFoo());
}
上面的代码不能阻止两个线程调用 createFoo
,这可能是一个昂贵的(或破坏性的!)操作。您需要使用同步块来避免两个线程之间的 race condition。
那么,你把模型放在哪里?好吧,您有多种选择。最简单的方法之一是将所有内容保存在用户的 session
中。会话是一种特定于用户的结构,可用于所有 HttpServletRequest
对象,因此它始终可用于 servlet。不过,这仅在用户实际登录到您的应用程序时才有效。现在让我们假设您确实有用户并且他们有自己的会话。
会话会根据发出请求的用户的身份自动与请求相关联。您需要的任何其他数据都应该来自请求本身(可能是来自 query string 的请求 参数 )。
您可以将任何您想要的内容放入会话中。描述您的 "business objects" 的自定义 classes(您在特定应用程序中用来表示概念的东西)优于包含其他 Map
s 命名集合的 Map
对象, Lists
s 等。我见过完全使用标准 Java 库 classes 构建的 Web 应用程序,它们是一堆地图查找和魔法列表索引。不要落入那个陷阱:编写自己的 classes.
用户模型数据的另一种选择是将其存储在某种数据库中。 "database" 有很多选择,从简单的文件存储到关系数据库再到 document/column/index 存储。他们都有自己的长处和短处。但是它们存储数据,您可以将用户模型数据放入数据库中。你如何识别用户?可能通过在会话中存储用户 ID。 (所以它通常都回到会话)。您还可以使用用户的用户名(可从请求中获得)在数据库中查找用户的数据。
无论如何,您应该不在 servlet 的 class 成员中存储任何关于用户状态(包括工作流等)的信息。如果你避免这样做,你就不会担心 servlet 中的线程安全。
另一个问题是共享资源。该问题的解决方案是确保以线程安全的方式使用这些共享资源。这通常可以通过池化资源来完成,例如数据库的连接池、消息队列、搜索索引等。解决这些问题通常非常特定于共享资源的类型,因此您可能想问一个更具体的问题当你到达那个阶段时。