请求队列实现

时间:2012-12-04 13:37:25

标签: java rpc request-queueing

我目前正在为RPC层做POC。我已经编写了以下方法来限制客户端的请求。这是一个很好的模式吗?我没有选择将其他请求排队到线程池中,因为我只对同步调用感兴趣,并且我希望调用程序线程阻塞,直到它被唤醒以执行RPC请求,并且因为创建了额外的线程,所以线程池似乎是额外的开销。

我以为我可以管理已经发出请求的线程。这种方法效果很好,但CPU使用率对其他进程有点不公平,因为一旦呼叫结束,另一个呼叫就会消失。我负载测试它与大量的请求和内存和CPU使用率是稳定的。我能以某种方式使用ArrayBlockingQueue与poll实现相同吗? poll()是不是太占用了CPU?

注意:我认识到requestEnd方法存在一些并发问题,它可能无法正确唤醒所有已注册的项目,我正在考虑采用一种高效的方法来维护原子性。

 public class RequestQueue {    
    // TODO The capacity should come from the consumer which in turn comes from
    // config
    private static final int _OUTBOUND_REQUEST_QUEUE_MAXSIZE = 40000;
    private static final int _CURRENT_REQUEST_QUEUE_INCREMENT = 1;
    private static final int _CURRENT_REQUEST_POOL_MAXSIZE = 40;
    private AtomicInteger currentRequestsCount = new AtomicInteger(0);
    private ConcurrentLinkedQueue<RequestWaitItem> outboundRequestQueue = null;

    public RequestQueue() {
        outboundRequestQueue = new ConcurrentLinkedQueue<RequestWaitItem>();
    }



    public void registerForFuture(RequestWaitItem waitObject) throws Exception {
        if (outboundRequestQueue.size() < _OUTBOUND_REQUEST_QUEUE_MAXSIZE) {
            outboundRequestQueue.add(waitObject);
        } else {
            throw new Exception("Queue is full" + outboundRequestQueue.size());
        }
    }

    public void requestStart() {
        currentRequestsCount.addAndGet(_CURRENT_REQUEST_QUEUE_INCREMENT);
    }

    //Verify correctness
    public RequestWaitItem requestEnd() {
        int currentRequests = currentRequestsCount.decrementAndGet();
        if (this.outboundRequestQueue.size() > 0 && currentRequests < _CURRENT_REQUEST_POOL_MAXSIZE) {
            try {
                RequestWaitItem waitObject = (RequestWaitItem)this.outboundRequestQueue.remove();               
                waitObject.setRequestReady(true);
                synchronized (waitObject) {
                    waitObject.notify();
                }   
                return waitObject;
            } catch (NoSuchElementException ex) {
                //Queue is empty so this is not an exception condition
            }
        }
        return null;
    }

    public boolean isFull() {
        return currentRequestsCount.get() > _CURRENT_REQUEST_POOL_MAXSIZE;
    }

}




public class RequestWaitItem {
    private boolean requestReady;
    private RpcDispatcher dispatcher;

    public RequestWaitItem() {
        this.requestReady = false;
    }

    public RequestWaitItem(RpcDispatcher dispatcher) {
        this();
        this.dispatcher = dispatcher;
    }

    public boolean isRequestReady() {
        return requestReady;
    }

    public void setRequestReady(boolean requestReady) {
        this.requestReady = requestReady;
    }

    public RpcDispatcher getDispatcher() {
        return dispatcher;
    }
}




if (requestQueue.isFull()) {
        try {               
                RequestWaitItem waitObject = new RequestWaitItem(dispatcher);               
                requestQueue.registerForFuture(waitObject);
                //Sync              
                // Config and centralize this timeout
                synchronized (waitObject) {
                    waitObject.wait(_REQUEST_QUEUE_TIMEOUT);
                }

                if (waitObject.isRequestReady() == false) {
                    throw new Exception("Request Issuing timedout");
                }
                requestQueue.requestStart();
                try {
                    return waitObject.getDispatcher().dispatchRpcRequest();
                }finally {
                    requestQueue.requestEnd();
                }               
        } catch (Exception ex) {
            // TODO define exception type
            throw ex;
        }
    } else {
        requestQueue.requestStart();
        try {
            return dispatcher.dispatchRpcRequest();
        }finally {              
            requestQueue.requestEnd();
        }
    }

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您希望通过最多40个(比方说)并发请求来限制对远程服务的请求。您可以使用信号量轻松完成此操作,无需额外的线程或服务。

Semaphore s = new Semaphore(40);
...
s.acquire();
try {
    dispatcher.dispatchRpcRequest(); // Or whatever your remote call looks like
} finally {
    s.release();
}

答案 1 :(得分:0)

请使用ExecutorService service = Executors.newFixedThreadPool(10);

这将在最多10个线程创建,进一步的请求将在队列中等待。我想这应该会有所帮助。

Fixed Thread Pool