2

假设我有一个被调用的方法doSomething(),并且我想在多线程应用程序中使用这个方法(每个 servlet 都继承自 HttpServlet)。我想知道在以下情况下是否会出现竞争条件:

  1. doSomething()不是静态方法,它将值写入数据库。
  2. doSomething()静态方法,但它不会将值写入数据库。

我注意到我的应用程序中的许多方法可能会导致竞争条件或脏读/写。例如,我有一个投票系统,对于每个投票操作,某种方法将更改该投票的单个单元格值,如下所示:

[poll_id |              poll_data        ]
[1       | {choice_1 : 10, choice_2 : 20}]

JSP/Servlets 应用程序会自己解决这些问题,还是我必须自己解决所有这些问题?

谢谢..

4

5 回答 5

4

这取决于如何doSomething()实施以及它实际上做了什么。我假设写入数据库使用 JDBC 连接,这不是线程安全的。这样做的首选方法是创建ThreadLocalJDBC 连接。

至于第二种情况,这取决于方法中发生了什么。如果它不访问任何共享的、可变的状态,那么就没有问题。如果是这样,您可能需要适当地锁定,这可能涉及为对这些变量的所有其他访问添加锁定。

(请注意,仅将这些方法标记为synchronized并不能修复任何并发错误。如果doSomething()在共享对象上增加一个值,那么对该变量的所有访问都必须是synchronized因为i++不是原子操作。如果它像增加一个计数器,你可以使用AtomicInteger.incrementAndGet()。)

于 2010-05-04T18:21:14.260 回答
3

Servlet API 当然不会神奇地使并发对您来说不是问题。

写入数据库时​​,取决于持久层中的并发策略。悲观锁定,乐观锁定,最后获胜?当您“写入数据库”时,还有更多事情要做,您需要决定如何处理。当两个人同时单击按钮时,您希望发生什么?

将 doSomething 设为静态似乎与该问题没有太大关系。那里发生的事情是相关的部分。是修改静态变量吗?那么是的,可能存在竞争条件。

于 2010-05-04T18:24:10.163 回答
2

servlet api 不会为您做任何事情来使您的并发问题消失。在 servlet 上使用 synchronized 关键字是个坏主意,因为您基本上是在一次处理一个线程,这会破坏您快速响应多个用户的能力。

如果您使用 Spring 或 EJB3,任何一个都将提供线程本地数据库连接和指定事务的能力。您绝对应该检查其中之一。

于 2010-05-04T18:30:14.733 回答
2

案例 1,您的 servlet 使用了一些访问数据库的代码。数据库具有您应该利用的锁定机制。造成这种情况的两个重要原因:数据库本身可能被其他读取和写入该数据的应用程序使用,这不足以让您的应用程序处理与自身的竞争。并且:您自己的应用程序可能会部署到一个扩展的、集群的 Web 容器中,您的代码的多个副本在不同的机器上执行。

因此,有许多标准模式用于处理数据库中的锁,您可能需要阅读悲观和乐观锁。

servlet API 和 JBC 连接池为您提供了一些有用的保证,因此您可以在不使用 Java 同步的情况下编写 servlet 代码,前提是您的变量在方法范围内,在概念上您有

   Start transaction (perhaps implicit, perhaps on entry to an ejb)
   Get connection to  DB ( Gets you a connection from pool, associated with your tran)
   read/write/update code
   Close connection (actually keeps it for your thread until your transaction commits)
   Commit (again maybe implictly)

所以你唯一真正的问题是处理数据库中的任何争用。如今,使用诸如 JPA 之类的东西,上述所有内容往往会做得更好,但在幕后或多或少是正在发生的事情。

案例2:静态方法,这大概意味着您现在将所有内容都保存在内存结构中。这(除非某种远程调用)暗示一个单一的 JVM 并且您管理自己的锁定。如果您的 JVM 或机器崩溃,我猜您会丢失数据。如果您关心您的数据,那么使用数据库可能会更好。

或者,完全不同的方法怎么样:servlet 通过将消息写入持久 JMS 队列来简单地记录“投票”。让其他一些进程从队列中获取选票并将它们添加起来。您不会以这种方式立即向选民提供反馈,但您将用户体验与实际(在类似场景中)相当复杂的处理脱钩。

于 2010-05-04T19:06:07.710 回答
0

我认为解决您问题的最佳方法是使用“同步”关键字并等待/通知!

于 2010-05-04T18:15:00.500 回答