3

I'm in the following situation.

There are several threads that can read/update MonthlySales persistent objects. Problem is that these objects may not exist and have to be dynamically created upon request.
So, two different threads my end up creating the entity corresponding to the same key (i.e. having the same ID), thus one of them failing to commit. I don't want this to happen. I would like one of the two threads to win the race and the other one to loose, waiting until the object has been created by the other.

In other words, I do want to do serialized transactions. Should I put an explicit Java lock (i.e. synchronized block)?

My current code is the following:

MonthlySales ms = entityManager.find(MonthlySales.class, somekey);
if (ms == null) { // two threads might enter this block altogether
    ms = new MonthlySales();
    // prepare ms object populating its fields with default values
    entityManager.persist(ms);
    entityManager.flush();
}
entityManager.lock(ms, LockModeType.PESSIMISTIC_WRITE); // lock this object
                                                        // since we are going to update it
// do something with ms object
entityManager.getTransaction().commit();
entityManager.close();

Can you help me?

gd1
  • 11,300
  • 7
  • 49
  • 88

1 Answers1

1

One way of avoiding a race condition is to let the thread / process / etc with the lowest ID win.

I believe you can access the thread ID using

long threadID = Thread.currentThread().getId();

from within the thread in Java. This is a better race condition solution than blocking the other threads, because that would defeat the purpose of using more than one thread.

See the Critical-Section Bakery Algorithm:

http://www.basicsofcomputer.com/critical_section_problem_in_operating_system.htm

In the case of JPA, according to here and here, the best practice approach seems to be trying to modify things at the same time, and catching exceptions if things don't work out.

Community
  • 1
  • 1
Alex W
  • 37,233
  • 13
  • 109
  • 109
  • 1
    This is an "handcrafted" solution, I need a JPA-oriented best practice. Moreover, blocking threads doesn't break the purpose of having more than one thread: it's called synchronization. Finally, the lowest-id-win solution has been deprecated because it causes some threads to starve. Now we have complex algorithms to manage synchronization that respect the fairness concept. – gd1 Jun 13 '12 at 03:52
  • I remember something from OS class specifically addressing this. I believe the solution was to have each process, or thread in this case, take a "ticket" or "number" like you would in a fast food restaurant to get into the critical section. Then you would let the threads with the lowest number go first. After it leaves the critical section, if it wants to re-enter it has to take a new number. This should preserve fairness and prevent starvation. I added a link to my answer. – Alex W Jun 13 '12 at 04:02
  • OK, look, I appreciate your efforts, but we're not writing an OS in assembler here. :) I'm looking for a Java solution to a Java problem, and it has to be something the most abstract and high-level possible. I'm not interested in low-level, non reusable solutions. However, the solution to my problem is the one of serializing transactions through explicit synchronization. See: http://stackoverflow.com/questions/2992463/jpa-atomic-query-save-for-multithreaded-app – gd1 Jun 13 '12 at 04:56
  • I was just trying to give the low-level solutions in case you were going to have to implement it yourself, however I did add that link to my answer when I posted my last comment. – Alex W Jun 13 '12 at 13:42