0

一連の等しくない入力値が与えられた場合 (一部の入力は他の入力よりも解決しやすい場合があります)、単一の答えを見つけるためにマルチスレッド アプローチを実装する方法 (1 つの「正しい」入力に基づくスレッドの 1 つ)

したがって、たとえば、複数のスレッドを使用して、これらの配列で特定の文字を見つけて返します (実際のプログラムでは明らかに大きなデータ セットを使用します)。

Inputs

[A, B, C, D, E, F]
[G, H]
[I, J, K]
[L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]

ターゲット要素が見つかったら、スレッドから呼び出し元の関数 (親スレッド) に返す必要があり、他のすべてのスレッドを強制終了できます。

私が検討したこと:

スレッド プール (「通常の」スレッド、エグゼキュータ スレッド) を使用して実行し、呼び出し元の関数 (パブリック変数?) で戻り値を設定します。

答えが見つかるまでメインスレッドをブロックする循環バリア

4

5 に答える 5

2

他のタスクによって共有およびポーリングされる回答を使用して AtomicReference を設定し、停止する必要があるかどうかを確認できます。これを使用して、待機中のスレッドに notify() することもできます。

final AtomicReference result = ...
// adds tasks
synchronized(result) {
    while(result.get() == null)
          result.wait();
}

// to check there is no answer. It doesn't have to be synchronized 
// as the value is thread safe.
while(result.get() == null) {


// in the task when a result is found.
synchronized(result) {
    result.set(answer);
    result.notifyAll();
}

ExecutorService を使用します。

于 2012-04-17T07:28:27.670 に答える
1

私はそれをすべて自分で行うことを好みます。物事を台無しにするより良い機会を提供しますが、柔軟性も高めます。私は制御フィールドから始めます:

public volatile boolean  foundIt = false;
public final boolean[]   jobList = { true, true, ..., true };
public final Object      threadLock = new Object();
public final Object      controllerLock = new Object();

(それらは実際には公開されるべきではありません。管理できる最小限の可視性を与えてください。) 次に、各スレッドを開始し、検索する配列と、完了時にオフにするブール値をそれぞれに知らせます (index以下の )。次のコマンドでコントローラーを一時停止します。

synchronized (controllerLock)  { controllerLock.wait(); }

スレッド内の Runnable は定期的にチェックfoundItして、まだ false であることを確認する必要があります。true の場合、シャットダウンする必要があります。同期は必要ありません。答えが見つかると、検索コードは次のように実行する必要があります。

haveAnswer:  {
    if (foundIt)  break haveAnswer;   // Already found by another thread.
    synchronized (threadLock)  {
        // Only one thread at a time can get into this block.
        if (foundIt)  break haveAnswer;   // Found since previous check.
        foundIt = true;
    }
    // Add code here to put answer in right place.
    // Only one thread will get this far.
}

シャットダウンするときは、検索配列の最後に到達したか、それfoundItが真であることに気付いたか、答えを見つけたかにかかわらず、次で終了します。

synchronized (controllerLock)  {
    jobList[index] = false;    // Tell world this thread is done.
    for (boolean active : jobList)
        if (active)
            // Another thread is still running.
            return;
    // This was the last thread. We're done. Restart controller.
    controllerLock.notifyAll();
}
于 2012-04-17T17:04:36.837 に答える
0

ExecutorCompletionService を使用して、見つかった結果を処理できます。必要な結果が得られたら、残りのタスクをキャンセルします。

このアプローチで私が気に入っているのは、タスクが単純なままであることです。彼らは、仕事のやり方を知り、いつキャンセルされたかを検出する必要があるだけです。

次に、タスクの作成者が処理結果を処理し、残りの作業をいつキャンセルするかを決定します。

于 2012-04-17T15:58:59.137 に答える
0

作業スレッドにコントローラーへの参照を追加します (コントローラーはすべてのスレッドのリストを保持します)。

コントローラーには、結果が見つかったことを通知するメソッドがあり、そのメソッドは結果を保存し、すべてのスレッドを強制終了/中断します。

于 2012-04-17T07:24:28.280 に答える
0

どういうわけか、結果を探しているスレッドは、結果が見つかったことを確認する必要があります。これは、中断されてから中断フラグをチェックすることで実行できます (InyerruptedExceprion をスローするメソッドはすべてこのチェックを行います。

また、結果キューや条件変数などの他の状態を見て確認することもできます。

例えば:

while (resultQueue.isEmpty()) {
    do a small amount of work
}

中断された状態を確認するには:

while (!Thread.interrupted()) {
    do a small amount of work
}
于 2012-04-17T07:28:21.030 に答える