まあ、おそらく初期化するのを忘れたでしょう:
private final AtomicInteger highestBid = new AtomicInteger();
ただしhighestBid
、ロックせずに作業するには、多くの知識が必要です。たとえば、新しい最高入札額で更新したい場合:
public boolean saveIfHighest(int bid) {
int currentBid = highestBid.get();
while (currentBid < bid) {
if (highestBid.compareAndSet(currentBid, bid)) {
return true;
}
currentBid = highestBid.get();
}
return false;
}
またはよりコンパクトな方法で:
for(int currentBid = highestBid.get(); currentBid < bid; currentBid = highestBid.get()) {
if (highestBid.compareAndSet(currentBid, bid)) {
return true;
}
}
return false;
なぜそんなに難しいの?と思うかもしれません。2 つのスレッド (リクエスト) が同時に入札しているイメージ。現在の最高入札額は 10 です。一方は 11 を入札し、もう 1 つは 12 を入札しています。両方のスレッドが現在highestBid
を比較し、それらの方が大きいことに気付きます。ここで、たまたま 2 番目のスレッドが最初になり、それを 12 に更新します。残念ながら、最初の要求が介入して 11 に戻します (条件が既にチェックされているため)。
これは典型的な競合状態であり、明示的な同期によって、または暗黙的な比較と設定の低レベル サポートを備えたアトミック変数を使用することによって回避できます。
よりパフォーマンスの高いロックフリーのアトミック整数によって導入された複雑さを見て、従来の同期に戻したいと思うかもしれません:
public synchronized boolean saveIfHighest(int bid) {
if (highestBid < bid) {
highestBid = bid;
return true;
} else {
return false;
}
}