バックグラウンド
学校にお金がないので、私は料金所で夜勤をしていて、インターネットを使ってコーディングスキルを学び、明日の仕事や自分が作ったアプリのオンライン販売を望んでいます。長い夜、少数の顧客。
マルチスレッドを使用する文献(Android SDKなど)で多くのコードに遭遇したため、トピックとしてマルチスレッドに取り組んでいますが、それでもあいまいです。
精神
この時点での私のアプローチは次のとおりです。考えられる最も基本的なマルチスレッドの例をコーディングし、壁に頭をぶつけて、脳を伸ばして新しい考え方に対応できるかどうかを確認します。私は自分の限界にさらされて、うまくいけば限界を超えようとしています。自由に批判し、私がやろうとしていることを行うためのより良い方法を指摘してください。
目的
Get some advice on how to do the above, based on my efforts so far (code provided)
エクササイズ
私が定義するスコープは次のとおりです。
意味
データオブジェクトの生成とその消費に連携して機能する2つのクラスを作成します。一方のスレッドはオブジェクトを作成し、もう一方のスレッドが取得して消費できるようにそれらを共有スペースに配信します。Producer
生成スレッド、消費スレッドConsumer
、共有スペースと呼びましょうSharedSpace
。他の人が消費するためにオブジェクトを作成するという行為は、このシナリオとの類似性によって同化することができます。
`Producer` (a busy mum making chocolate-covered cakes for his child, up to a limit)
`Consumer` (a hungry child waiting to eat all cakes the mum makes, until told to stop)
`SharedSpace` (a kitchen table on which the cakes are put as soon as they become ready)
`dataValue` (a chocolate-dripping cake which MUST be eaten immediately or else...)
運動を簡単にするために、私は子供がケーキを食べるときに母親が料理をすることを許可しないことにしました。彼女は子供がケーキを完成させるのを待つだけで、良い子育てのために、ある限界まで、即座に別のケーキを作ります。演習の本質は、並行性を実現することよりもスレッドのシグナリングを練習することです。それどころか、私は完全なシリアル化に焦点を合わせており、ポーリングや「まだ行けますか?」はありません。チェックします。次に、母と子が並行して「働く」という後続の演習をコーディングする必要があると思います。
アプローチ
クラスにRunnableインターフェイスを実装してもらい、独自のコードエントリポイントを設定します。
プログラムのエントリポイント からインスタンス化および開始されるThreadオブジェクトへのコンストラクター引数としてクラスを使用します
main
Thread.join()を使用して、スレッド
main
が終了する前にプログラムが終了しないことを確認します。Producer
のデータを作成する回数に制限を設定しますConsumer
データ生成の終了を通知するために使用する番兵の値について合意します
Produce
ワーカースレッドの最終的なサインオフを含む、共有リソースおよびデータの生成/消費イベントのロックのログ取得
プログラムから単一の
SharedSpace
オブジェクトを作成し、main
開始する前にそれを各ワーカーに渡しますオブジェクトへの
private
参照SharedSpace
を各ワーカーの内部に保存しますConsumer
データが生成される前に消費する準備ができている状態を説明するためのガードとメッセージを提供しますProducer
指定された回数の反復後に停止しますConsumer
番兵の値を読み取った後、停止します
コード
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class Consumer extends Threaded {
public Consumer(SharedSpace sharedSpace) {
super(sharedSpace);
}
@Override
public void run() {
super.run();
int consumedData = 0;
while (consumedData != -1) {
synchronized (sharedSpace) {
logger.info("Acquired lock on sharedSpace.");
consumedData = sharedSpace.dataValue;
if (consumedData == 0) {
try {
logger.info("Data production has not started yet. "
+ "Releasing lock on sharedSpace, "
+ "until notification that it has begun.");
sharedSpace.wait();
} catch (InterruptedException interruptedException) {
logger.error(interruptedException.getStackTrace().toString());
}
} else if (consumedData == -1) {
logger.info("Consumed: END (end of data production token).");
} else {
logger.info("Consumed: {}.", consumedData);
logger.info("Waking up producer to continue data production.");
sharedSpace.notify();
try {
logger.info("Releasing lock on sharedSpace "
+ "until notified of new data availability.");
sharedSpace.wait();
} catch (InterruptedException interruptedException) {
logger.error(interruptedException.getStackTrace().toString());
}
}
}
}
logger.info("Signing off.");
}
}
class Producer extends Threaded {
private static final int N_ITERATIONS = 10;
public Producer(SharedSpace sharedSpace) {
super(sharedSpace);
}
@Override
public void run() {
super.run();
int nIterations = 0;
while (nIterations <= N_ITERATIONS) {
synchronized (sharedSpace) {
logger.info("Acquired lock on sharedSpace.");
nIterations++;
if (nIterations <= N_ITERATIONS) {
sharedSpace.dataValue = nIterations;
logger.info("Produced: {}", nIterations);
} else {
sharedSpace.dataValue = -1;
logger.info("Produced: END (end of data production token).");
}
logger.info("Waking up consumer for data consumption.");
sharedSpace.notify();
if (nIterations <= N_ITERATIONS) {
try {
logger.info("Releasing lock on sharedSpace until notified.");
sharedSpace.wait();
} catch (InterruptedException interruptedException) {
logger.error(interruptedException.getStackTrace().toString());
}
}
}
}
logger.info("Signing off.");
}
}
class SharedSpace {
volatile int dataValue = 0;
}
abstract class Threaded implements Runnable {
protected Logger logger;
protected SharedSpace sharedSpace;
public Threaded(SharedSpace sharedSpace) {
this.sharedSpace = sharedSpace;
logger = LoggerFactory.getLogger(this.getClass());
}
@Override
public void run() {
logger.info("Started.");
String workerName = getClass().getName();
Thread.currentThread().setName(workerName);
}
}
public class ProducerConsumer {
public static void main(String[] args) {
SharedSpace sharedSpace = new SharedSpace();
Thread producer = new Thread(new Producer(sharedSpace), "Producer");
Thread consumer = new Thread(new Consumer(sharedSpace), "Consumer");
producer.start();
consumer.start();
try {
producer.join();
consumer.join();
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
}
実行ログ
Consumer - Started.
Consumer - Acquired lock on sharedSpace.
Consumer - Data production has not started yet. Releasing lock on sharedSpace, until notification that it has begun.
Producer - Started.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 1
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 1.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 2
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 2.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 3
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 3.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 4
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 4.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 5
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 5.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 6
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 6.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 7
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 7.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 8
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 8.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 9
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 9.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: 10
Producer - Waking up consumer for data consumption.
Producer - Releasing lock on sharedSpace until notified.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: 10.
Consumer - Waking up producer to continue data production.
Consumer - Releasing lock on sharedSpace until notified of new data availability.
Producer - Acquired lock on sharedSpace.
Producer - Produced: END (end of data production token).
Producer - Waking up consumer for data consumption.
Producer - Signing off.
Consumer - Acquired lock on sharedSpace.
Consumer - Consumed: END (end of data production token).
Consumer - Signing off.
質問
- 上記は正しいですか?(たとえば、正しい言語ツール、正しいアプローチを使用しているか、愚かなコードが含まれているかなど)
しかし、それは「正しく見える」のでしょうか?
「もう一方」ではなく「一度」のテストで何回問題が発生したか想像できないため、出力が「見栄えが良い」場合でも正確性について質問します(たとえば、コンシューマーが最初に開始したとき、プロデューサーが終了しなかったときなど)。歩哨などを作成した後)。私は「成功した実行」から正しさを主張しないことを学びました。それどころか、私は疑似並列コードに非常に疑いを持っています!(これは定義上並列ではありません!0
拡張された回答
良い質問は(上記のもの)だけに焦点を当てていone requested piece of advice
ますが、必要に応じて、回答の中で次の他のトピックへの洞察を自由に述べてください。
次の試行をコーディングするときに、並列コードをテストするにはどうすればよいですか?
開発とデバッグの両方で役立つツールはどれですか?Eclipseを使用することを検討してください
生産を継続することを許可した場合、アプローチは変更されますか?
Producer
各生産にはさまざまな時間がかかりますが、Consumer
利用可能になるものはすべて消費されますか?ロックは他の場所に移動する必要がありますか?シグナリングは、この待機/通知パラダイムから変更する必要がありますか?物事を行うこの方法は時代遅れですか、そして私はむしろ何か他のものを学ぶべきですか?この料金所からは、「Javaの現実の世界」で何が起こっているのかわかりません。
次のステップ
- ここからどこへ行けばいいの?「未来」の概念がどこかで言及されているのを見たことがありますが、トピックの番号付きリストを使用して、関連する学習リソースへのリンクを使用して、順番に、教育的に順序付けて作業することができます
ティノシノ