在Tomcat中,Servlet并发/同步处理?

3
有没有推荐的方法来同步Tomcat Servlet实例,这些实例竞争相同的资源(比如一个文件,或者一个不是ACID的MongoDB数据库)?
我熟悉线程同步以确保两个Java线程不会同时访问同一个Java对象,但不熟悉具有超出JRE范围存在的对象的同步。
编辑:我只有1个Tomcat服务器正在运行。无论这是否意味着不同的JVM,我不确定(我假设它是相同的JVM,但可能是不同的线程)。
编辑:特定用例(但我是在一般情况下提出问题):
Tomcat服务器充当文件存储,将原始文件放入目录中,并使用MongoDB存储元数据。这是一个非常简单的概念,除了并发问题。如果有两个并发请求同时存储相同的文件,或者同时管理相同对象的元数据,我需要解决这个问题,但不确定如何解决。我想最简单的方法是以某种方式序列化/排队请求。有办法在Tomcat中实现排队吗?

它们是否都将在同一JVM中运行,还是有可能在不同的Tomcat实例中运行? - John Munsch
5个回答

3
通常情况下,您的各种servlet将在同一个JVM中运行,如果它们没有,则应该能够配置您的servlet运行程序以使其成为这种情况。因此,您可以安排它们查看某些中央共享资源管理器。
然后对于实际的gubbinry,如果普通的同步不合适,请查看例如Semaphore类(链接是我一段时间前写的教程/示例的一部分,以防有用),它允许您处理“池”资源。

那么您可以安排让它们看到一些集中的、共享的资源管理器,这是指我应该创建某种单例吗? - Jason S
没错,确切地说——创建一个单例类,其中包含静态方法getDatabasePool()、getCacheManager()等,你可以从任何一个servlet中调用它们。 - Neil Coffey
如果你要添加这种瓶颈,那么他最好使用Tomcat的SingleThreadedServlet(或类似策略)。 - Gandalf
我无法评论海报是否打算添加瓶颈,但在原则上,在服务器之间共享资源是完全有效的做法。 - Neil Coffey

3
如果您正在运行一个Tomcat服务器,并且所有的servlet都在一个context中,您可以始终在该context类加载器上存在的Java对象上进行同步。如果您运行多个context,则“同步对象”不能驻留在任何特定的context中,而是需要驻留在所有context共享的更高级别。您可以使用Tomcat 6.0文档这里中的“公共”类加载器来将您的“同步对象”放置在那里,然后它将在所有context之间共享。

2

我有两种情况,如果您希望在同一JVM中访问通用的文件编辑资源,则可以在Java函数中使用“synchronized”。如果不同的JVM和其他非Java线程访问通用资源,则可以尝试使用手动文件锁定代码,在队列中为每个线程分配优先级编号。

对于数据库,我认为没有并发问题。


1

你的外部资源将以某种方式由Java对象(例如java.io.File)表示。如果需要,您可以始终在该对象上进行同步。

当然,这意味着该对象必须在您的Servlet实例之间共享。


1
这进一步意味着存在一些内部软件来控制代表有争议的资源的代理对象的创建。截至今天,没有任何东西可以阻止多个代码片段都创建自己的文件对象,这些对象都代表同一个文件。因此,您必须拥有某种单例工厂,以确保每个有争议的资源只有一个对象。 - John Munsch
@ChssPly76:不是,不是,不是(John说的话)-- 如果你执行这段代码 { File f1 = new File("/usr/bin"); File f2 = new File("/usr/bin"); System.out.println(f1==f2); } 你会得到false,因此在一个文件上同步不影响能否在另一个文件上获得锁。 - Jason S
@Jason - “said object would have to be shared” 的哪一部分意味着可以创建两个 File 的副本? - ChssPly76

1

我认为你这样做会带来麻烦。数据库和共享文件系统之类的东西被发明出来是有原因的。试图使用一些Singleton类或信号量编写自己的存储解决方案会很快变得混乱不堪。找一个能够为你完成这项工作的存储解决方案,可以避免很多麻烦。


1
我并不打算编写自己的程序,我只是想了解在具有分离、可能并发的Tomcat请求时,正确处理写入文件或MongoDB的推荐方式。 - Jason S
我的答案是 - 不建议这样做。 - Gandalf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接