Java methods and race condition in jsp / servlets application
Suppose I have a method called doSomething()
and I want to use this method in a multithreaded application (each servlet inherits from HttpServlet). I am wondering if it is possible for a race condition to occur in the following cases:
-
doSomething()
not a static method and it writes values to the database. -
doSomething()
static method, but it does not write values to the database.
what I've noticed is that many methods in my application can lead to race conditions or messy read / write. for example, I have a poll system, and for each voting operation, a certain method will change the value of one cell for that poll as follows:
[poll_id | poll_data ]
[1 | {choice_1 : 10, choice_2 : 20}]
Will the JSP / Servlets application solve these problems on its own or should I solve it all myself?
Thanks..
a source to share
It depends on how it is implemented doSomething()
and what it actually does. My guess is that writing to the database is using JDBC connections, which are not thread safe. The preferred way to do this would be to create ThreadLocal
JDBC connections .
As for the second case, it depends on what happens in the method. If it doesn't have access to shared, mutable state, then the problem doesn't arise. If so, you will probably need to lock appropriately, which could involve adding locks to any other access to these variables.
(Remember that simply marking these methods as synchronized
not fixing any concurrency errors. If incremented doSomething()
for a shared object, then all calls to this variable should be synchronized
, since it is i++
not an atomic operation. If it is as simple as incrementing a counter, you can use AtomicInteger.incrementAndGet()
.)
a source to share
The Servlet API certainly doesn't magically make concurrency a problem for you.
When writing to the database, it depends on the concurrency strategy in your persistence level. Pessimistic blocking, optimistic blocking, the last to win? There's more going on when you write to the database that you need to decide how you are going to handle. What do you want to do when two people press the button at the same time?
Making doSomething static doesn't seem to affect the problem too much. What's happening in it is the important part. Is this changing static variables? Then yes, there may be race conditions.
a source to share
The api servlet will not do anything for you to make your concurrency problems go away. Things like using a synchronized keyword on your servlets are a bad idea because you basically force your threads to be processed one at a time, and this ruins your ability to respond quickly to multiple users.
If you are using Spring or EJB3, one of these will provide threadlocal database connections and the ability to specify transactions. You should definitely check one of them.
a source to share
Case 1, your servlet uses some code that accesses the database. Databases have locking mechanisms that you must use. There are two important reasons for this: the database itself can be used from other applications that read and write this data, this is not enough for your application to cope with the struggle with itself. And: your own application can be deployed to a scalable clustered web container, where multiple copies of your code are executed on separate machines.
So there are many standard patterns for dealing with locking in databases, you may need to read Pessimistic vs. Optimistic Locking.
Combining the Servlet API and JBC Connections gives you some useful guarantees so that you can write your servlet code without using Java Synchronization, if your variables are in method scope, in concept you have
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)
So your only real problem is with any statements in the DB. All of the above tends to be done more beautifully using things like JPA these days, but under the covers, which is more or less what's going on.
Case 2: static method, this seems to imply that you are now storing everything in a memory structure. This (disallowing remote invocation of any kind) creates a single JVM and you manage your own locking. If your JVM or machine crashes, I think you will lose your data. If you care about your data, then it might be better to use a DB.
OR, how about a completely different approach: the servlet simply records the "vote" by writing the message to a persistent JMS queue. Ask other processes to pick up votes from the queue and add them. You won't give immediate voter feedback this way, but you will separate the user from the actual (in similar scenarios) rather complex processing.
a source to share