我有一个任务队列,以及一个在几秒钟内查看队列一次的线程,如果有任务它会执行它。
我有另一个代码部分(当然在另一个线程中),它在循环中创建任务(我无法从循环外部提前知道任务的数量)并将它们插入队列。任务包含一些“结果”对象,外部线程(创建这些任务)需要等待所有任务完成并最终从每个任务中获取结果。问题是我无法将 java Semaphore\CountDownLatch 等传递给结果对象,因为我事先不知道监视器的数量。我也不能使用使用 invokeAll 的 Executor 或等待 Future 对象,因为任务是不同步的(外部线程只是将任务推送到队列中,另一个线程将在他有时间时执行任务)。
我想到的唯一解决方案是创建一些“反转信号量”类,该类包含一组结果和一个监视器计数器。getResult 函数将检查计数器是否 == 0,如果答案是肯定的,将通知某个锁对象,getResult 函数将等待此锁:
public class InvertedSemaphore<T> {
Set<T> resultSet;
int usages;
final Object c;
public InvertedSemaphore() {
resultSet = Collections.synchronizedSet(new HashSet<T>());
usages = 0;
c = new Object();
}
public void addResult(T result) {
resultSet.add(result);
}
public void addResults(Set<T> result) {
resultSet.addAll(result);
}
public void acquire() {
usages++;
}
public void release() {
synchronized (c) {
if (--usages == 0) {
c.notify();
}
}
}
public Set<T> getResults() {
synchronized (c) {
try {
while (usages > 0) {
c.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return resultSet;
}
}
每个 addTask 方法都会调用 semaphore.acquire,每个(未同步的)任务都会在任务结束时调用 semaphore.release。
这听起来很复杂,我很确定在 java 并发库或其他东西中有更好的解决方案。
任何想法都会被应用:)