views:

243

answers:

5

Hi. Suppose that I have a method called doSomething() and I want to use this method in a multithreaded application (each servlet inherits from HttpServlet).I'm wondering if it is possible that a race condition will occur in the following cases:

  1. doSomething() is not staic method and it writes values to a database.
  2. doSomething() is static method but it does not write values to a database.

what I have noticed that many methods in my application may lead to a race condition or dirty read/write. for example , I have a Poll System , and for each voting operation, a certain method will change a single cell value for that poll as the following:

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

will the JSP/Servlets app solve these issues by itself, or I have to solve all that by myself?

Thanks..

A: 

I thing that the best solution for your problem is to use something like "synchronized" keyword and wait/notify!

kafrlust
In servlets this appraoch is rarely the best solution.
djna
+3  A: 

It depends on how doSomething() is implemented and what it actually does. I assume writing to the database uses JDBC connections, which are not threadsafe. The preferred way of doing that would be to create ThreadLocal JDBC connections.

As for the second case, it depends on what is going on in the method. If it doesn't access any shared, mutable state then there isn't a problem. If it does, you probably will need to lock appropriately, which may involve adding locks to every other access to those variables.

(Be aware that just marking these methods as synchronized does not fix any concurrency bugs. If doSomething() incremented a value on a shared object, then all accesses to that variable need to be synchronized since i++ is not an atomic operation. If it is something as simple as incrementing a counter, you could use AtomicInteger.incrementAndGet().)

Mike
Thanks Mike. Yes,I use JDBC , and I'll read about ThreadLocal,thanks again .
BugKiller
The Servlet API and other JEE APIs simplifies much of this. Your local variables in your servlet's methods are effectively thread local (for the duration of the service request). JDBC connection pooling in app servers will give each thread it's own connection. Most difficulties occur where the different threads contend, in this case probably in the database itself. As Affe says this is where the real design work starts.
djna
+3  A: 

The Servlet API certainly does not magically make concurrency a non-issue for you.

When writing to a database, it depends on the concurrency strategy in your persistence layer. Pessimistic locking, optimistic locking, last-in-wins? There's way more going on when you 'write to a database' that you need to decide how you're going to handle. What is it you want to have happen when two people click the button at the same time?

Making doSomething static doesn't seem to have too much bearing on the issue. What's happening in there is the relevant part. Is it modifying static variables? Then yes, there could be race conditions.

Affe
+2  A: 

The servlet api will not do anything for you to make your concurrency problems disappear. Things like using the synchronized keyword on your servlets are a bad idea because you are basically forcing your threads to be processed one at a time and it ruins your ability to respond quickly to multiple users.

If you use Spring or EJB3, either one will provide threadlocal database connections and the ability to specify transactions. You should definitely check out one of those.

Nathan Hughes
+2  A: 

Case 1, your servlet uses some code that accesses a database. Databases have locking mechanisms that you should exploit. Two important reasons for this: the database itself might be used from other applications that read and write that data, it's not enough for your app to deal with contending with itself. And: your own application may be deployed to a scaled, clustered web container, where multiple copies of your code are executing on separate machines.

So, there are many standard patterns for dealing with locks in databases, you may need to read up on Pessimistic and Optimistic Locking.

The servlet API and JBC connection pooling gives you some helpful guarantees so that you can write your servlet code without using Java synchronisation provided 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 issue is dealing with any contentions in the DB. All of the above tends to be done rather more nicely using things such as JPA these days, but under the covers thats more or less what's happening.

Case 2: static method, this presumably implies that you now keep everything in a memory structure. This (barring remote invocation of some sort) impies a single JVM and you managing your own locking. Should your JVM or machine crash I guess you lose your data. If you care about your data then using a DB is probably better.

OR, how about a completely other approach: servlet simply records the "vote" by writing a message to a persistent JMS queue. Have some other processes pick up the votes from the queue and adds them up. You won't give immediate feedback to the voter this way, but you decouple the user's experience from the actual (in similar scenarios) quite complex processing .

djna