この演習の核心は、スレッドセーフでアトミックな方法でカウンター (注文数) を更新しているように私には思えます。正しく実装されていない場合、更新が行われず、別のスレッドでカウンターの古い値が表示される可能性があるため、ショップは 5000 を超える予約注文を受け取ることになる可能性があります。
カウンターをアトミックに更新する最も簡単な方法は、synchronized
メソッドを使用してカウンターを取得およびインクリメントすることです。
class DonutShop {
private int ordersTaken = 0;
public synchronized int getOrdersTaken() {
return ordersTaken;
}
public synchronized void increaseOrdersBy(int n) {
ordersTaken += n;
}
// Other methods here
}
同期されたメソッドは、常に 1 つのスレッドのみがいずれかのメソッドを呼び出すことができることを意味します (また、古い可能性があるローカルにキャッシュされた値ではなく、異なるスレッドが同じ値を参照することを保証するためのメモリ バリアも提供します)。これにより、アプリケーション内のすべてのスレッドで一貫したカウンター ビューが保証されます。
(「set」メソッドではなく「increment」メソッドがあることに注意してください。「set」の問題は、クライアントが を呼び出さなければならない場合shop.set(shop.get() + 1);
、別のスレッドが と の呼び出しの間に値をインクリメントする可能性があるget
ためset
、この更新インクリメント操作全体をアトミックにすることにより (同期ブロック内にあるため)、このような状況は発生しません。
実際には、おそらく代わりにAtomicIntegerを使用します。これは基本的に、上のクラスint
と同様に、アトミックなクエリと更新を可能にするのラッパーです。DonutShop
また、排他的ブロッキングを最小限に抑えるという点でより効率的であるという利点もあり、標準ライブラリの一部であるため、自分で作成したクラスよりも他の開発者にとってすぐに馴染みます。
正確さに関しては、どちらでも十分です。