首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用CompletableFuture避免使用“阻塞”等待

使用CompletableFuture避免使用“阻塞”等待
EN

Stack Overflow用户
提问于 2018-08-18 15:48:20
回答 1查看 575关注 0票数 2

这是一个阻塞系统(同步)。其背后的想法是:

  1. 如果我们的webapp接收到N个相同的请求(生成相同的“缓存id”的N个不同的Tomcat http请求),那么只将第一个请求发送到api服务器,其余的就会在这个‘缓存id’上被阻塞。
  2. 当第一个请求结束并从api服务器接收到响应时,这个响应将存储在我们的缓存中。
  3. 在此之后,将调用“解锁”方法来唤醒在这个‘缓存id’上阻塞的所有线程(其余的N-1请求)。
  4. 这个N-1请求被唤醒,他们查询缓存,找到这个‘缓存id’的响应,所以它们不会被发送到api服务器,所以这个api保存来处理它们。

这是一种尝试从缓存中获取文档的方法(简化)。

代码语言:javascript
复制
public dtoCache getDocumentFromCache(String cacheId)
{
 dtoCache objCache = CacheFacade.getInstance().getCacheEntry(cacheId);

 // If document not found in cache ...
 if (objCache == null)
 {
  // If I'm the first, just return null (and the process to send the request 
  // to the server will start outside this method). Otherwise block on this method.
  if (!this.objLockAndAwait.lock(cacheId)) return null;

  // At this point the first request with this 'cacheId' saved the document on cache, 
  // so after awaking go to cache again because we will find the document there.
  return (this.getDocumentFromCache(cacheId));  
 }

 return (objCache);
}

'lock‘方法非常简单,如果'mapCacheId’包含'cacheId‘键,只需参考。

代码语言:javascript
复制
public boolean lock(String cacheId)
{
  // Get a 'lockObject' for this 'cacheId' and acquire it.
  LockObject lockObject = this.stripedLock.getLockObject(cacheId);
  lockObject.lock();

  try
  {
   // Check if this 'cacheId' is going to the server right now. Two cases:
   // 1. If the map does not contain this 'cacheId' --> don't block, I'm the 
   // first --> return false and continue
   // 1. If the map contains this 'cacheId' --> block on it.
   if (this.mapCacheId.putIfAbsent(cacheId, (byte)0) != null)
   {
    lockObject.await(cacheId);
    return true;
   }

   return false;
  }
  finally { lockObject.unlock(); }
}

这就是“解锁”方法,每次请求来自服务器时都会调用它。它在“cacheId”上发出信号,唤醒所有阻塞在它上的线程。

代码语言:javascript
复制
public void unlock(String cacheId)
{
  LockObject lockObject = this.stripedLock.getLockObject(cacheId);
  lockObject.lock();

  try
  {
   lockObject.signalAll(cacheId);
   this.mapCacheId.remove(cacheId);
  }
  finally { lockObject.unlock(); }
}

现在,我需要重写这段代码,使其成为异步的。我不希望线程在等待条件下被阻塞,如果一个线程由于“mapCacheId”中找到'cache id‘而必须被阻塞,我需要释放这个线程来接受另一个任务,并且只有在通知发送到服务器的请求完成后,才会在回调中重新捕获代码。

我正在检查'CompletableFuture',因为它似乎是解决这个问题的方法,但是在玩了几天之后,我无法看到如何修改代码,使其与CF异步。看来我需要这个N-1CF来等待第一个CF的完成,但是CF很复杂,我找不到任何类似的例子。

EN

回答 1

Stack Overflow用户

发布于 2018-08-19 03:17:01

class DtoCache extends CompletableFuture<Document>。然后

代码语言:javascript
复制
// webapp receives a request
public void handleRequest(Request request) {
   String cacheId = request.getCacheId();
   boolean first = false;
   DtoCache objCache;
   synchronized(cache) {
       objCache = cache.get(cacheId);
       if (objCache == null) {
           first = true;
           objCache = new DtoCache();
           cache.put(cacheId, objCache);
       }
   }
   if (first) {
       // only the first request asks the Api server
       Document doc = askApiServer(cacheId);
       // reply to our request
       request.reply(doc);
       // reply to the other requests
       objCache.complete(doc);
   } else {
      // arrange an asynchronous reply to our request
      objCache.thenApply(request::reply);
   }
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51910263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档