我正在尝试在 Java 中实现一个工作队列,以限制一次可以处理的工作量。特别是,它试图保护对外部资源的访问。我目前的方法是使用一个信号量和一个 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
并且,如果成功,则创建一个包装 Semaphore#release
的匿名 Callable调用try/finally
阻止对 work.call()
的调用.
这行得通,但有点不令人满意,因为如果此类的用户放置了某个实现 Callable 的特定类的工作,则在查看 tryPoll
的结果时,用户将无法访问该类。 .值得注意的是,tryPoll()
返回 Callable<Void>
, 不是 Work
.
有没有一种方法可以实现工作限制效果,同时向调用者返回对已提交工作对象的可用引用? (加强 LimitingQueue
的类型签名使其更像 LimitingQueue<R, T extends Callable<R>>
很好。)我想不出一种方法来确保在调用工作项后释放信号量而不进行这种包装。
最佳答案
EDIT2 我已经用关于如何实现您正在寻找的内容的建议替换了此处的内容。如果您想恢复一些旧信息,请告诉我,我可以恢复它。
public class MyQueue<T> {
private Semaphore semaphore;
public void put(Work<T> w) {
w.setQueue(this);
}
public Work<T> tryPoll() {
return null;
}
public abstract static class Work<T> implements Callable<T> {
private MyQueue<T> queue;
private void setQueue(MyQueue<T> queue) {
if(queue != null) {
throw new IllegalStateException("Cannot add a Work object to multiple Queues!");
}
this.queue = queue;
}
@Override
public final T call() throws Exception {
try {
return callImpl();
} finally {
queue.semaphore.release();
}
}
protected abstract T callImpl() throws Exception;
}
}
然后像这样使用它:
public class Test {
public static void main(String[] args) {
MyQueue<Integer> queue = new MyQueue<Integer>();
MyQueue.Work<Integer> work = new MyQueue.Work<Integer>() {
@Override
protected Integer callImpl() {
return 5;
}
};
queue.put(work);
MyQueue.Work<Integer> sameWork = queue.tryPoll();
}
}
关于java - 如何以类型友好的方式包装可调用对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6406896/