2

オブザーバーパターンとBlockingQueueを使用してインスタンスを追加しています。別のメソッドでキューを使用していますが、次のように実行しているにもかかわらず、take()が永久に待機しているようです。

/** {@inheritDoc} */
@Override
public void diffListener(final EDiff paramDiff, final IStructuralItem paramNewNode,
    final IStructuralItem paramOldNode, final DiffDepth paramDepth) {
    final Diff diff =
        new Diff(paramDiff, paramNewNode.getNodeKey(), paramOldNode.getNodeKey(), paramDepth);
    mDiffs.add(diff);
    try {
        mDiffQueue.put(diff);
    } catch (final InterruptedException e) {
        LOGWRAPPER.error(e.getMessage(), e);
    }
    mEntries++;

    if (mEntries == AFTER_COUNT_DIFFS) {
        try {
            mRunner.run(new PopulateDatabase(mDiffDatabase, mDiffs));
        } catch (final Exception e) {
            LOGWRAPPER.error(e.getMessage(), e);
        }
        mEntries = 0;
        mDiffs = new LinkedList<>();
    }
}

/** {@inheritDoc} */
@Override
public void diffDone() {
    try {
        mRunner.run(new PopulateDatabase(mDiffDatabase, mDiffs));
    } catch (final Exception e) {
        LOGWRAPPER.error(e.getMessage(), e);
    }
    mDone = true;
}

一方、mDiffQueueはLinkedBlockingQueueであり、次のように使用しています。

while (!(mDiffQueue.isEmpty() && mDone) || mDiffQueue.take().getDiff() == EDiff.INSERTED) {}

しかし、mDoneがtrueではないのに最初の式がチェックされていると思います。その後、mDoneがtrueに設定されている可能性があります(オブザーバーは常にマルチスレッドですか?)が、すでにmDiffQueue.take()を呼び出していますか?:-/

編集:私は本当に今それを取得していません。最近、次のように変更しました。

synchronized (mDiffQueue) {
    while (!(mDiffQueue.isEmpty() && mDone)) {
        if (mDiffQueue.take().getDiff() != EDiff.INSERTED) {
            break;
        }
    }
}

デバッガーで少し待つと動作しますが、mDoneがfalseに初期化され、while条件がtrueになり、本体が実行されるため、「リアルタイム」でも動作するはずです。

mDiffQueueが空で、mDoneがtrueの場合、whileループの本体をスキップする必要があります(つまり、キューはもういっぱいになりません)。

編集:それはそうです:

synchronized (mDiffQueue) {
    while (!(mDiffQueue.isEmpty() && mDone)) {
         if (mDiffQueue.peek() != null) {
             if (mDiffQueue.take().getDiff() != EDiff.INSERTED) {
                 break;
             }
         }
    }
}

なぜpeek()が必須なのかわかりませんが。

編集:

私がしているのはツリーを反復処理することであり、すべてのINSERTEDノードをスキップしたいと思います。

for (final AbsAxis axis = new DescendantAxis(paramRtx, true); axis.hasNext(); axis.next()) {
    skipInserts();
    final IStructuralItem node = paramRtx.getStructuralNode();
    if (node.hasFirstChild()) {
        depth++;
        skipInserts();
        ...

基本的に、ツリーの別のリビジョンで削除されたノードを考慮せずに、ツリーの最大深度またはレベルを計算します(サンバーストの視覚化の比較のため)が、それは範囲外である可能性があります。最大深度を調整しているだけでも、挿入されていないノードで何かをしていることを説明するためだけに。

よろしく、

ヨハネス

4

2 に答える 2

2

take()「ブロッキングコール」です。つまり、キューに何かが入るまでブロック(永久に待機)し、追加されたものを返します。もちろん、何かがキューにある場合、それはすぐに戻ります。

によって返されるpeek()ものを返すために使用できます。take()つまり、キューから削除せずpeek()に次のアイテムを返すか、キューに何もない場合に戻ります。代わりにテストで使用してみてください(ただし、nullも確認してください)。nullpeek()

于 2011-09-07T11:51:15.153 に答える
1

最初のアドバイス:しないでくださいsynchronized (mDiffQueue)。LinkedBlockingQueueに何らかのsynchronizedメソッドがあると、デッドロックが発生します。ここではそうではありませんが、避けるべき習慣です。とにかく、なぜその時点で同期しているのかわかりません。

mDone設定されているかどうかを確認するのを待つ間、定期的に「ウェイクアップ」する必要があります。

while (!(mDiffQueue.isEmpty()  && mDone)) {
   // poll returns null if nothing is added in the queue for 0.1 second.
   Diff diff = mDiffQueue.poll(0.1, TimeUnit.SECONDS); 
   if (diff != null)
      process(diff);
}

これは、を使用する場合とほぼ同じですpeekが、peek基本的にはナノ秒待機します。使用peekは「ビジー待機」(スレッドがwhileループをノンストップで実行する)とpool呼ばれ、使用は「セミビジー待機」(スレッドを一定間隔でスリープさせる)と呼ばれます。

あなたの場合、がタイプでないprocess(diff)場合はループから抜け出すことになると思います。それがあなたが成し遂げようとしていることであるかどうかはわかりません。基本的に、適切なタイプの単一の要素を取得するまでコンシューマースレッドを停止し、その後は何もしないため、これは奇妙に思えます。また、whileループから外れているため、将来の着信要素を受け取ることはできません。diffEDiff.INSERTED

于 2011-09-07T12:50:36.667 に答える