2010-05-04 57 views
2

假设我有一个方法名为doSomething(),我想在多线程应用程序中使用此方法(每个servlet都继承自HttpServlet)。我想知道是否有可能竞态条件会发生以下情况:jsp/servlets应用程序中的java方法和竞争条件

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

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

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

将JSP/Servlet的应用程序通过本身解决这些问题或者我必须自己解决所有这些问题?

谢谢..

回答

4

这取决于doSomething()的实现方式以及它的实际功能。我假设写入数据库使用JDBC连接,它们是而不是线程安全。这样做的首选方法是创建ThreadLocal JDBC连接。

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

(注意,只是标记这些方法如​​不能解决任何并发错误。如果doSomething()递增一个共享对象上的值,则所有访问该变量需要被​​因为i++不是一个原子操作。如果它就像增加一个计数器一样简单,你可以使用AtomicInteger.incrementAndGet()。)

+0

谢谢迈克。是的,我使用JDBC,我会读到有关ThreadLocal的内容,再次感谢。 – Abdullah 2010-05-04 20:37:43

+1

Servlet API和其他JEE API简化了这些。您的servlet方法中的本地变量实际上是线程本地的(在服务请求期间)。应用程序服务器中的JDBC连接池将为每个线程提供自己的连接。大多数困难发生在不同的线程竞争,在这种情况下可能在数据库本身。情绪表示,这是真正的设计工作开始的地方。 – djna 2010-05-04 20:54:33

0

我东西,你的问题的最佳解决方案是使用类似“同步”的关键字,并等待/通知!

+0

在servlets中这个appraoch很少是最好的解决方案。 – djna 2010-05-04 20:56:38

3

Servlet API当然不会奇迹般地让并发成为非问题。

写入数据库时​​,它取决于持久层中的并发策略。悲观锁定,乐观锁定,最后赢家?当你“写入数据库”时,你需要决定如何处理,还有更多的事情要做。你是什​​么意思想要当两个人同时点击按钮时发生?

制作doSomething静态似乎没有太多的问题。那里发生的是相关的部分。它是否修改静态变量?那么是的,可能会有竞争条件。

2

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

如果您使用Spring或EJB3,则任何一个都将提供线程本地数据库连接以及指定事务的能力。你一定要看看其中的一个。

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队列来简单记录“投票”。让其他进程从队列中提取投票并添加它们。您不会以这种方式立即向选民提供反馈,但是您可以将用户的体验与实际(在类似场景中)的相当复杂的处理分离开来。