如何在Java中同时确保只有一个请求

时间:2018-04-12 09:36:23

标签: java android kotlin

我想实施一个名为:

的电话
public Response getContent() throws MyException

此方法在内部调用Web服务,但我只希望同时向Web服务发出一个请求。也就是说:当第一个请求到来时,它将转到Web服务。如果同时另一个请求到达,则等待第一个请求的结果。在第一个请求返回(或抛出异常)之后,所有挂起的请求也会返回(或抛出异常)。从这一点开始,如果另一个请求到来,它将再次转到具有相同标准的Web服务(同时只有一个Web服务调用)

在Java / Android中实现此功能的最佳方法是什么?

由于

2 个答案:

答案 0 :(得分:3)

这是一个CompletableFuture的解决方案,它始终阻止等待新结果。如果您调用get()并且存在现有结果,则会触发新的提取和阻止。如果提取已在进行中,它将加入等待该结果的其他线程。

import java.util.concurrent.CompletableFuture
import java.util.concurrent.atomic.AtomicReference

class OneAtATime<out T> {
    private val pending = AtomicReference(CompletableFuture<T>())
    init {
        startFetching(pending.get())
    }

    fun get(): T {
        val current = pending.get()
        if (!current.isDone) {
            return current.get()
        }
        val next = CompletableFuture<T>()
        return if (pending.compareAndSet(current, next)) {
            startFetching(next)
            next.get()
        } else {
            pending.get().get()
        }
    }

    private fun startFetching(future: CompletableFuture<T>) {
        TODO("Implementation must call future.complete(newContent)")
    }
}

答案 1 :(得分:1)

我建议开始学习阻塞队列的工作原理:
BlockingQueue

之后,您可以开始调查解决方案,以便一次拨打一个电话。一种解决方案是使用信号量:
Blocking queue with a semaphore

(来自上面的链接)适用于您的案例的摘录:
编辑

 public class CustomBlockingQueue {
  private List<Object> queue = new LinkedList<Object>();
  private int limit;
  private Semaphore mutex; // for the critical section
  public CustomBlockingQueue() {
    this.mutex = new Semaphore(1);
  }
  //enqueue can be process task, etc.
  private void enqueue(Object o) throws InterruptedException {
    mutex.acquire(); // critical section starts
    queue.add(o); //or custom operation
    mutex.release(); // critical section ends
  }

  //as pointed out in the comments this is more queue related
  private Object dequeue() throws InterruptedException {
    mutex.acquire(); // critical section starts
    Object o = queue.remove(0);//or custom operation
    mutex.release(); // critical section ends
    return o;
  }
}