Reputation: 1136
My main goal is to be able to have some synchronized method that shouldn't be accessed by other threads until it is finished. If I had usual VM - I would mark this method as synchronized. But in GAE I have multiple instances. All posts that I read about this say that I should use memcache or datastore. But how exactly ?
Upvotes: 5
Views: 2629
Reputation: 19
Actually I don't use that kind of synchronization a lot. Once I did. It seems to work pretty well. Here is an example
String syncKey = "Sync:" + req.getRequestURI();
boolean lockAcquired = false;
try {
lockAcquired = acquireLock(syncKey, 5000L);
if (!lockAcquired) {
return;
}
// do something here
} finally {
if (lockAcquired) {
memcacheService.delete(syncKey);
}
}
public boolean acquireLock(String syncKey, long maxwait) {
long start = System.currentTimeMillis();
while (true) {
if (memcacheService.increment(syncKey, 1L, 0L) == 1L) {
return true;
}
if (System.currentTimeMillis() - start > maxwait) {
return false;
}
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
}
}
}
Usually I use more simpler synchronization. It gives me opportunity to run some piece of code only once.
final long now = System.currentTimeMillis() / (60L * 1000L); // expire every minute
if (memcacheService.increment("VoteRemoveOldTask" + now, 1L, 1L) == 1L) {
QueueFactory.getDefaultQueue().add(
TaskOptions.Builder.withDefaults().url(VoteRemoveOldTask.URL));
}
Upvotes: 1
Reputation: 15143
Usually the answer is redesign the function so it doesn't need to be globally synchronized. Even if you manage to synchronize it, it's a single bottleneck.
You're probably best off to implement it on a backend; you can specify a single backend, and make your function call a request to the backend. You can also use memcache or the datastore as semaphore, but all of those are going to give you poor performance.
Upvotes: 6