Issue
We have the following code to execute in Java:
public void doSomething() {
doSomeDBOperationForOrg();
doOtherOperations();
}
void doSomeDBOperationForOrg() {
//should be executed only once per organization.
}
void doOtherOperations() {
//should be executed only when the DB operation for the organization is done, and not before
}
The method doSomething
is being called at the same time by multiple users under multiple organizations. We need to execute method doSomeDBOperationForOrg
only once per organization, and doOtherOperations
for all the users calling the doSomething
method, but only after doSomeDBOperationForOrg
is complete.
One option is to have "synchronized" over doSomething
and/or doSomeDBOperationForOrg
, and maintain a list of updated orgaizations.
public synchronized void doSomething() {
if(!orgUpdatedList.contains(organization)) {
doSomeDBOperationForOrg();
orgUpdatedList.add(organization);
}
doOtherOperations();
}
But that will block all the threads from users irrespective of their organizations. This is not desirable, when we have a huge list of users. Can someone please advise a better way to achieve this?
Solution
You want to execute doOtherOperations();
freely in parallel, so this should not be in any (effective) synchronized
block.
But you want doSomeDBOperationForOrg();
to happen once per organization. As you deal with multiple threads, requirements like "once per xyz" need some sort of synchronization.
And you don't want users to wait for initialization of an organization they don't belong to.
Suggestions:
If you have a class (let's call it Organization
) representing the organizations (in the sense that one organization is mapped 1:1 to exactly one instance, without duplicate instances for the same organization), then you can make doSomeDBOperationForOrg();
a synchronized instance method of the Organization
class, and have this method check whether the initialization is necessary. Then doSomething()
is quite simple:
public void doSomething() {
organization.doSomeDBOperationForOrg();
doOtherOperations();
}
Or, closer to you current structure:
public void doSomething() {
synchronized (organization) {
if(!orgUpdatedList.contains(organization)) {
doSomeDBOperationForOrg();
orgUpdatedList.add(organization);
}
}
doOtherOperations();
}
But make sure, you use a thread-safe orgUpdatedList
, e.g. by wrapping Collections.synchronizedXyz()
around it!
By synchronizing on the organization, you make sure that users from one organization can block one another, so that there's an orderly initialization, but aren't affected by users from other organizations.
If you don't have an appropriate Organization
class (and can't introduce one), but only a String
, you can synchronize on organization.intern()
. That method has the property that all Strings with the same content result in the identical instance. It's kind of a hack, but should work.
Answered By - Ralf Kleberhoff
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.