我目前正在为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();
}
}
答案 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个线程创建,进一步的请求将在队列中等待。我想这应该会有所帮助。