Google App Engine. How to make synchronized action

2019-05-07 09:57发布

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 ?

2条回答
该账号已被封号
2楼-- · 2019-05-07 10:05

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.

查看更多
Lonely孤独者°
3楼-- · 2019-05-07 10:22

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));
}
查看更多
登录 后发表回答