2

2つのスレッドがGenericObjectPoolから2つの再利用可能なインスタンスを要求し、次のデータセット応答で作業を開始します-

Thread 1 [ Rec1, Rec1, Rec2 ]

Thread 2 [ Rec1, Rec3, Rec2 ]

Thread 3 [ Rec3 ]

これらのレコードは最初に検索する必要があります。見つからない場合は、テーブルのセットにのみ挿入されます。したがって、thread1では、Rec1が2回発生すると、順次実行されるため、安全に処理されます。ただし、プールから2番目のインスタンスのThread2にもRec1があるため、インスタンス間で競合が発生するため、Rec2と同様に、Rec3も繰り返されます。

そして、クラス自体は次のようになります-

Method1
--------
loop on all records
check condition1 
If Meets
lock obj
Recheck condition1
if meets
INSERT1
release lock
end loop

と ..

Method 2
---------
loop on all records
check condition2 
If Meets
lock obj
Recheck condition2
if meets
INSERT2
release lock
end loop

「obj」ロックに関する提案?静的finalにすると解決しますが、クラスレベルのロックを多用するため、プログラムはほぼシーケンシャルになります。

4

2 に答える 2

1

java.util.concurrent.ConcurrentLinkedQueue独自のロック機構の代わりに使用してみてください。シンプル、高速、実用的なノンブロッキング

問題が正しいことを理解していれば、method1 と method2 にそれぞれ 2 つの異なるキューが必要になります。また、呼び出されるステップはloop on all records次のように定義されますget element from queue or wait

于 2013-02-27T06:12:55.337 に答える
1

操作の実行中はロックを保持しないでください。同期呼び出しを使用して、誰がどのレコードで作業するかを調停し、同期ブロック内ではなく操作を実行し、完了したら信号を送ります。

だから(Javaで):

private final static Object LOCK = new Object();
private final static Set<Integer> busyRecords = new HashSet<Integer>();

public static void waitToWorkOn(int recordNum) {
   synchronized(LOCK) {
      while (busyRecords.contains(recordNum)) {
         LOCK.wait(); //go to sleep
      }
      busyRecords.add(recordNum); //ours now
   }
}

public static void doneWith(int recordNum) {
   synchronized(LOCK) {
      busyRecords.remove(recordNum);
      LOCK.notifyAll(); //wake sleepers up
   }
}

これを使用するすべてのコードは、try-finally を使用してリリース シグナルが確実に送信されるようにする必要があります。

waitToWorkOn(recordNum);
try {
   //do something to record
} finally {
   doneWith(recordNum);
}
于 2013-02-27T05:53:08.593 に答える