2011-01-27 11 views
1

ループ内の一部のリスナーに通知します。リスナーを呼び出すときに許容される最大処理時間を設定します。

for (Iterator it = listeners.iterator(); it.hasNext();) { 
    MyListener l = (MyListener) it.next(); 
    l.notifyEvent(event); 
} 

私は、リスナーが通知メソッド内で何をしているのか見当がつかない - それは非常に長い時間がかかる可能性があるかの入力を待ってブロックすること。 システムの応答性を保証するために、次のリスナーで処理を続ける前に最大限の処理時間を確保したいと考えています。

メソッド呼び出しの最大処理時間を保証するために受け入れられるパターンは何ですか?私は二つの可能性を考える

  • は、通知のための新しいスレッドを生成しました。それが時間内に戻らない場合は、新しいスレッドを作成し、次のリスナーをそのスレッドとともに処理します。最終的に最初のものが返ってきたら、ただそれを消させてください。この戦略のコード例を挙げることができますか?
  • 現在処理中のリスナースレッドに割り込みを送信し、これがリターンすることを期待します。

他のアイデアやベストプラクティスはありますか?

PS:Java 1.4でjava.util.concurrentバックポートを使用しているため、j.u.c構造が使用できます。

編集:ここで私が開発した解決策です。 ExecutorServicesを使用するので、この単純な目的を達成するには少し重いです。そのスレッドがリスナに詰まるまで、追加のスレッドは1つだけ使用されます。次に、新しいExecutorService内に新しいスレッドが生成され、次のリスナーと連携します。注:このソリューションは、スレッドセーフでも同時実行可能でもありません。リスナーが独立している、とあなたは彼らの「回答」または任意のコールバックを気にしないならば、あなたは、単にリスナーに通知し、各リスナーのためのスレッドを生成することができれば1つのスレッドだけdoNotify()

private final Queue listeners = new ConcurrentLinkedQueue(); 
private final long timeout; 
private final TimeUnit unit; 
private ExecutorService threadPool = Executors.newFixedThreadPool(1); 

public void doNotify(){ 
    for (Iterator it = listeners.iterator(); it.hasNext();) { 
     final MyListener l = (MyListener) it.next(); 
     Future future = threadPool.submit(new Runnable() { 
      public void run() { 
       l.notifyEvent(); 
      } 
     }); 
     try { 
      future.get(timeout, unit); // wait for task to be executed 
     } catch (InterruptedException e1) { 
      // ignore for now 
     } catch (ExecutionException e1) { 
      // ignore for now 
     } catch (TimeoutException e1) { 
      threadPool.shutdown(); // pool accepts no new tasks, and will exit when done 
      threadPool = Executors.newFixedThreadPool(1); // make new thread for next listener 
     } 
    } 
} 

答えて

1

を呼び出す必要があります。彼らにを与える場合は、が完了するまでに時間がかかる場合は、各スレッドのThread.join(millis)にタイムアウトを呼び出すことができます。

スレッドの最大数が気になる場合は、スレッドプールを使用して同じアプローチを使用できます。しかし、 "ブロッキング"リスナーの数がスレッドプール内のスレッドの数を超えると、少し問題になります。

Thread.stopは、good reasonsで非推奨となっています。

+0

ありがとうございます。私はそれに基づいて構築します。多くのリスナーにとって、あなたのソリューションは、私が避けたいと思う多くのスレッドを生成します。新しいスレッドは、必要な場合にのみ作成する必要があります(通常のリスナーが時間通りに応答すると仮定します)。 – Philipp

+0

@Philipp、まあ、そういうわけで、私はスレッドプールを代替デザインの選択肢と言いました。 – aioobe

0

リスナーのコードを制御しないので、ほとんどのリスナーは、イベントディスパッチスレッド上で実行されているという前提で書かれています。スレッドをバックグラウンドで実行すると、スレッドセーフではないAWTまたはSwingメソッドが呼び出される可能性があります。

これが特定のMyListenerインターフェイスに制限されている場合は、少なくともMyListener.notify()がEDTで呼び出されることが保証されていないというjavadocに警告を追加する必要があります。

+0

*「ほとんどのリスナーは、イベントディスパッチスレッドで実行されているという前提で書かれます」* ... AWT/Swingリスナーについて話していると仮定していますか? – aioobe

+1

私の質問は、スイング/ AWTではなく一般的なスレッドに関することです。何か重要なことがあれば、何かをする前にスレッドが何を呼び出すかを調べることができます。 – Philipp

+0

申し訳ありません。あなたがスレッドをブロックするのを避けるために探していて、リスナーが関与しているとすれば、問題のスレッドがEDTであり、リスナーがAWT/Swingイベントリスナーであったということは間違いありませんでした。結論に飛びついて申し訳ありません。 –

1

MyListenerのコードを制御しないと(新しいスレッドを生成しても)、無駄な時間を制御することはできません。スレッドにシャットダウンや割り込みを強制する方法や、許可された時間を尊重する方法はありません。

+0

*強制的にスレッドをシャットダウンする方法はありません*、まあ、 'Thread.stop'メソッドがありますが、それは極端な注意を払って使用する必要があります。 – aioobe

+0

'Thread.stop'は推奨されておらず、使用しないでください。 –

+0

Thread.stopは廃止されました。なぜなら、スレッドを "kill"して、使用していたリソースを解放する方法がわからないからです。 MyListenerのコードを制御してスレッドを強制終了しないと、失う可能性があるものを予測できません。そしてそれは何か重要であるはずです:) –

関連する問題