java - 如何以类型友好的方式包装可调用对象?

标签 java generics

我正在尝试在 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/

相关文章:

java - 使用线程在 JavaFX 中移动矩形

c# - 获取类实现的泛型接口(interface)的类型参数

具有实例化不同泛型接口(interface)的泛型类型参数的 Java 类

java - 扩展 ArrayList 以支持事件

java - 在java中查找OSX的版本

java - 使用java使用具有大数据的数组编写json文件

java - 如何在 fragment 中请求 WRITE_EXTERNAL_STORAGE 权限

java - 提高方法性能java

Swift 泛型和协议(protocol)不适用于 UIKit [可能的错误]

java - 确定通用类型字段的类类型