3

紛らわしいタイトルですみません。それをどのように表現するかがよくわかりません。それが問題かもしれません!

同時スレッドが関係する状況で使用するための適切な抽象化を探しています。

近づくことはできましたが、完全に釘付けにはなりませんでした。

少し単純化すると、Android フォンで収集されている 2 種類のセンサー入力があります。方向タイプのものと WiFi スキャンです。

両方が十分に収集されたら、データを使用するイベントをトリガーしたいと考えています。ただし、ここで停止したくありません。このプロセスは N 回継続する必要があります。

最初は、条件で while ループを使用しました。

startCollecting();
while (samplesCollected < X){
    // wait
    while (directionCount < Y || scanCount < Z){}; 
    // then
    doSomeStuff();
    samplesCollected++; 
}
stopCollecting();

ただし、これはパフォーマンスが悪いと SO から言われました。実際、UI のロックアップが発生しているため (別のスレッドにある場合でも)、java.util.concurrent を使用することにしました。

問題は、おそらく私の経験不足のせいで、どの抽象化を使用するかをうまく判断できないことです。

  • ReentrantLock の条件:

    条件のアイデアは素晴らしいようです-しかし、共有リソースを制御したい場合はそうではありません-最初のバッチが処理されている間、データ収集をバックグラウンドで続行したい-では、どこでロックを呼び出すのですか? ロックしないと、IllegalMonitorStateException がスローされます。

  • カウントダウンラッチ:

    理想的なようです-収集スレッドがデータを利用できる場合、countDown() を呼び出すことができ、countDown が十分な回数呼び出されると、アクションを続行できます。しかし、countDown は 1 回限りの実行であると想定されており、これを数回繰り返す必要があります。

  • サイクリックバリア:

    CountdownLatch のドキュメントでは、動作を繰り返し可能にする場合は代わりに CyclicBarrier を使用する必要があることを示唆していますが、CyclicBarrier の比喩はこの状況では完全に間違っているようで、これを使用する方法がわかりません。

以下にいくつかの関連する質問をリンクしました - ガイダンスをいただければ幸いです。

効率 - 変数の変更を待つループでの Thread.yield の使用

Javaスレッドに別のスレッドの出力を待機させる方法は?

Javaに「条件が真になるまでブロック」機能はありますか?

Java で wait() と notify() を使用する簡単なシナリオ

4

3 に答える 3

2

BlockingQueue(さまざまな)並行キューを使用したい場合があります。

センサーを読み取るスレッドからキューを埋めます (現在センサーを配置している構造にセンサーを配置するのではなく)。

ループでtakeは、データの一部であり、それが何であるか (向きまたは wifi) を調べ、正しいカウンターをインクリメントし、データをどこかに配置します (おそらく、ある種のローカル リスト)。十分なデータが得られたら、収集したデータを処理関数に渡します。

これが機能するのは、キューから何かを取得しようとするとスレッドがスリープ状態になり、使用できるものが何もないため、カウンターをポーリングすることはありません。

于 2013-05-02T03:18:41.990 に答える
2

コードにも同様の実装があります。runnable を実装し、データを処理できる内部クラスを作成しました。単一のスレッドでデータを読み取り続け、データのサイズが特定の制限に達すると、そのデータを内部クラスのインスタンスに渡し、その内部クラスのインスタンスをタスクとして ThreadPoolExecutor サービスに送信します。

これは私たちにとって非常にうまく機能します。

于 2013-05-02T03:25:52.207 に答える
1

コードの一部が待機中でビジーであるため、アプリがロックされますが、これは一般的に悪いことです。簡単に修正するThread.sleep(25)には、内側の while ループに a (または同等のもの) を追加すると、ロックが修正されます。

他のことを組み合わせてください...最初に、変数samplesCollecteddirectionCount、およびscanCountをマークvolatileするか、 にする必要がありますAtomicLong (or AtomicInteger)。そうしないと、別のスレッドで行われた変更が表示される保証がありません。その理由を理解するには、メモリ バリアについて、より具体的には Java メモリ モデルについて読んでください。

変数がスレッド セーフであることを確認して を追加Thread.sleep(...)すれば問題ありません (アプリがロックされることはなく、正しく機能するはずです) が、理想的な解決策ではありません。

ただし、これは理想的なソリューションではありません。このマスター スレッドは、各インクリメント後にワーカー スレッド自体がしきい値を超えているかどうかをチェックすることで、取り除くことができます。その場合、スレッドを開始して (または同じスレッドで)、集計後のコードを実行できます。同様に、特定の最大しきい値に達した場合、すべてのスレッドに収集を停止するよう信号を送ることができます。AtomicLong.incrementAndGet()スレッドがカウントを適切に処理するようにするために、これを適切に機能させるために使用する必要があります (機能しvolatileませ)。

于 2013-05-02T03:29:43.610 に答える