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