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?

1

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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.
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.
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: stackoverflow.com/questions/2992463/…
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.
0

Do it in two phases:

Phase 1:

get the monthly sales from the DB
if it does not exist {
  try {
    create it
    persist it
    flush
  } catch(exception when already exists) {
    // ignore
  }
} else {
  flush
}

Phase 2 in a transaction:

get the monthly sales from the DB
lock it
update it
commit

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.