2

ベクトル オブジェクトに値を設定する 1 つのスレッドと、そこから値を定期的にフェッチして定期的にクリアする別のスレッドがあります。

ベクトルにアクセスしているいずれかのスレッドが一時停止し、もう一方のスレッドがアクセスしている必要があります。wait/notify/notifyAll キーワードを使用する必要がありますか?

private Vector<Long> _recordIdsSent;

# Called by main thread (before thread A and thread B are started)
public ConstructorOfThisClass() {
    _recordIdsSent = new Vector<Long>();
    // Starts thread A & B
}

# Called by thread A
public void addSentRecordIds( List<Long> ids ) {
    synchronized (_recordIdsSent) {
        _recordIdsSent.addAll( ids );
    }
}

# Called by thread B
public void deleteRecords()
{
    List<Long> ids;
    synchronized (_recordIdsSent) {
        ids = (List<Long>) _recordIdsSent.clone();
        _recordIdsSent.clear();
    }

    // Delete the records matching ids....
}

注: 削除操作には時間がかかる可能性があるため、_recordIdsSent ベクターを複製します。

[編集] synchronized キーワードをメソッド シグネチャから変数 _recordIdsSent に移動しました

4

5 に答える 5

4

あなたはする必要はありません。のように同期ブロックを入れるaddSentRecordIdsだけですdeleteRecords。したがって、Vectorにアクセスできるのは一度に1つのスレッドだけです。

于 2011-07-26T17:03:36.067 に答える
1

既に述べたように、提供されたコードでは vector from へのアクセスがaddSentRecordIds同期されていないため、コードが安全ではなくなります

_recordIdsSentまた、このコード スニペットは、ロック ( )に使用されるオブジェクトが変更されないことを保証しません。これも安全ではありません。私自身は通常、ロック専用のオブジェクトを好みます。これは、意図が明確になり、エラーが発生しにくくなるためです。このような:

private final Object lock = new Object(); // dedicated lock object
//... _recordIdsSent, addSentRecordIds etc...
public void deleteRecords()
{
    List<Long> ids;
    synchronized (lock) {
        ids = (List<Long>) _recordIdsSent.clone();
        _recordIdsSent.clear();
   }

   // Delete the records matching ids....
}
于 2011-07-26T17:24:11.417 に答える
1

これは元の質問に対する回答ではなく、当面の問題に取り組む別の方法に関する提案です。

単一のスレッド プール (java.util.concurrent) を使用できます。

Executor executor = Executors.newSingleThreadExecutor();

DBに書き込み/削除したい場合:

executor.call(new Runnable() {
   @Override public void run() { ... write to DB}
});

executor.call(new Runnable() {
   @Override public void run() { ... delete in DB}
});

それらをどこで呼び出しても、同じスレッドで実行されます。

編集: newSingleThreadExecutor の javadoc から: 「無制限のキューで動作する単一のワーカー スレッドを使用する Executor を作成します。(ただし、シャットダウン前の実行中に失敗したためにこの単一のスレッドが終了した場合、新しいスレッドが代わりに使用されることに注意してください。後続のタスクを実行するために必要な場合.) タスクは順次実行されることが保証されます, 任意の時点で複数のタスクがアクティブになることはありません. それ以外の場合は同等の newFixedThreadPool(1) とは異なり、返されるエグゼキュータは追加のスレッドを使用するために再構成できないことが保証されます. ."

于 2011-07-27T16:36:27.813 に答える
0

同期されたキーワードがあなたのためにそれをしているので、あなたはそうする必要はありません。

同期とは、一度に1つのスレッドのみがそのブロック、またはクラス内の他の同期ブロックに入ることができることを意味します。つまり、クラスにスレッドセーフである必要がある2つの別個のオブジェクトがあり、それらの別個のオブジェクトの両方を同期として操作するメソッドを作成すると、オブジェクトの1つにアクセスするスレッドは、他のスレッドが他のスレッドにアクセスするのをブロックします。オブジェクト(理想的ではありません)なので、使いすぎないでください。そうしないと、マルチスレッドを使用することのすべての利点が打ち消されます。

于 2011-07-26T17:14:58.430 に答える
0

以前の投稿で述べたように、データ構造を変更するメソッドで synchronized キーワードを使用すると、データの同時アクセスと破損の可能性を防ぐことができます。

待機メソッドと通知メソッドを使用することの価値は、コンシューマー スレッド (データを読み取るスレッド) が常にポーリングする必要がなく、ベクトルが特定のサイズに達したときにプロデューサー スレッドから通知を受けることができることです。

于 2011-07-26T17:54:06.403 に答える