我正在尝试在Java中实现一个工作队列,它限制了每次可以处理的工作量。特别地,它试图保护对外部资源的访问。我的当前方法是使用Semaphore和BlockingQueue,以便我有类似这样的东西:
interface LimitingQueue<V> {
void put(Callable<V> work);
Callable<V> tryPoll();
}
它应该像这样运行:
@Test
public void workLimit() throws Exception {
final int workQueue = 2;
final LimitingQueue<Void> queue = new LimitingQueue<Void>(workQueue);
queue.put(new Work()); // Work is a Callable<Void> that just returns null.
queue.put(new Work());
// Verify that if we take out one piece of work, we don't get additional work.
Callable<Void> work = queue.tryPoll();
assertNotNull(work, "Queue should return work if none outstanding");
assertNull(queue.tryPoll(), "Queue should not return work if some outstanding");
// But we do after we complete the work.
work.call();
assertNotNull(queue.tryPoll(), "Queue should return work after outstanding work completed");
}
tryPoll()
的实现使用了 Semaphore#tryAcquire
,如果成功,就创建一个匿名的 Callable,将 Semaphore#release
调用包装在一个 try/finally
块中,该块围绕着对 work.call()
的调用。这种方法虽然可行,但有点不尽如人意。因为如果这个类的用户放入的工作是某个特定的 Callable 实现类,则当查看
tryPoll
的结果时,用户无法访问该类。值得注意的是,tryPoll()
返回的是一个 Callable<Void>
,而不是一个 Work
。有没有一种方法可以实现工作限制效果,并在将提交的工作对象返回给调用者时提供一个可用的引用?(将
LimitingQueue
的类型签名加强成更像 LimitingQueue<R, T extends Callable<R>>
是可以的。)我想不出在不进行此类包装的情况下确保在调用工作项后释放信号量的方法。