タスクのキューがあり、数秒に1回キューをピークするスレッドがあり、タスクがある場合はそれを実行します。
別のコードセクション(もちろん別のスレッド)があり、ループ内にタスクを作成し(ループの外側から事前にタスクの数を知ることはできません)、それらをキューに挿入します。タスクにはいくつかの「結果」オブジェクトが含まれており、外部スレッド(これらのタスクを作成した)は、すべてのタスクが終了するのを待って、最終的に各タスクから結果を取得する必要があります。問題は、モニターの数が事前にわからないため、結果オブジェクトにjava Semaphore\CountDownLatchなどを渡すことができないことです。また、タスクが同期されていないため、invokeAllを使用するExecutorを使用したり、Futureオブジェクトを待機したりすることはできません(外部スレッドはタスクをキューに入れるだけで、時間があるときに別のスレッドがタスクを実行します)。
私が考えていた唯一の解決策は、一連の結果とモニターカウンターを保持する「逆セマフォ」クラスを作成することです。getResult関数は、カウンター== 0であるかどうかを確認し、答えがyesの場合は、ロックオブジェクトに通知し、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並行ライブラリなどでこれに対するより良い解決策があると確信しています。
どんなアイデアでも適用されます:)