Java プログラムを作成する必要がありますが、自分で始める前にアドバイスが必要です。
私が書くプログラムは、次のことを行うことです。
ドーナツの事前注文を受ける店をシミュレートする
5000個のドーナツが注文されると、店はそれ以上の注文を受け付けません
わかりました、モニターとして機能するJavaクラスを作成する必要があるのか 、それとも代わりにJava-Semaphoreクラスを使用する必要があるのか 、考えに行き詰まっていますか?
私に助言してください。助けてくれてありがとう。
Java プログラムを作成する必要がありますが、自分で始める前にアドバイスが必要です。
私が書くプログラムは、次のことを行うことです。
ドーナツの事前注文を受ける店をシミュレートする
5000個のドーナツが注文されると、店はそれ以上の注文を受け付けません
わかりました、モニターとして機能するJavaクラスを作成する必要があるのか 、それとも代わりにJava-Semaphoreクラスを使用する必要があるのか 、考えに行き詰まっていますか?
私に助言してください。助けてくれてありがとう。
から継承された待機/通知メソッドを介して、任意の Java オブジェクトをモニターとして機能させることができますObject。
Object monitor = new Object();
// thread 1
synchronized(monitor) {
monitor.wait();
}
// thread 2
synchronized(monitor) {
monitor.notify();
}
これらのメソッドを呼び出すときは、モニター オブジェクトのロックを保持するようにしてください ( wait. このようにして、スレッド間でシグナルを送信するための便利なメカニズムが得られます。
境界のある生産者と消費者のキューを実装しているように思えます。この場合:
wait、共有モニターを呼び出してスリープ状態になります。notify、消費者が待っている場合は、モニターを呼び出して消費者を目覚めさせます。notifyアイテムを取得すると、モニターを呼び出してプロデューサーを起動します。waitてスリープ状態になります。さらに単純化されたアプローチについては、上記の機能をそのまま提供するBlockingQueueのさまざまな実装でループを作成してください。
この演習の核心は、スレッドセーフでアトミックな方法でカウンター (注文数) を更新しているように私には思えます。正しく実装されていない場合、更新が行われず、別のスレッドでカウンターの古い値が表示される可能性があるため、ショップは 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また、排他的ブロッキングを最小限に抑えるという点でより効率的であるという利点もあり、標準ライブラリの一部であるため、自分で作成したクラスよりも他の開発者にとってすぐに馴染みます。
正確さに関しては、どちらでも十分です。
Tudor が書いたように、任意のオブジェクトを汎用ロックと同期のモニターとして使用できます。
ただし、一度に x 注文 (この場合は x=5000) しか処理できないという要件がある場合は、このjava.util.concurrent.Semaphoreクラスを使用できます。これは、固定数のジョブしか実行できないユースケース向けに特別に作成されています。Semaphore
すぐに処理を行う場合は、
private Semaphore semaphore = new Semaphore(5000);
public void process(Order order)
{
if (semaphore.tryAcquire())
{
try
{
//do your processing here
}
finally
{
semaphore.release();
}
}
else
{
throw new IllegalStateException("can't take more orders");
}
}
それ以上かかる場合 (人間の入力が必要、別のスレッド/プロセスの開始など)、処理が終了したときのコールバックを追加する必要があります。
private Semaphore semaphore = new Semaphore(5000);
public void process(Order order)
{
if (semaphore.tryAcquire())
{
//start a new job to process order
}
else
{
throw new IllegalStateException("can't take more orders");
}
}
//call this from the job you started, once it is finished
public void processingFinished(Order order)
{
semaphore.release();
//any other post-processing for that order
}