OOユニット2-神秘的なエレベーター

1.設計戦略とプログラム構造分析

  1.最初の宿題

  最初の仕事では、マルチスレッドのリアルタイムエレベーターシステムをシミュレートする必要があります。関数は比較的単純で通常ですが、ピギーバック関数を使用するために、私が使用するスケジューリング戦略は、消費者生産者モデルを使用した、ガイドで提供されているALSスケジューリング戦略です。 、プロデューサーは入力クラスであり、継続的に人のエレベータリクエストを入力し、コンシューマはエレベータクラスであり、入力エレベータリクエストを継続的に受け入れ、実行を継続します。中間倉庫クラスはスケジューラであり、プロデューサが提供する入力クラスを格納します。要求し、特定のスケジューリング戦略の後で、実行するエレベーター要求をエレベーターに与えます。

  しかし、スケジューラはエレベーターのリアルタイムステータスを取得したいのですが、あるスレッドから別のスレッドを直接呼び出すことはできないため、この設計戦略を採用しました。エレベーターは独自の状態情報を保存し、エレベータースレッドの各実行サイクルの開始時に取得します。進行方向については、エレベーターは上昇しているか下降しているかにのみ責任があり、上昇しているか、下降している理由には関与しません。つまり、エレベーターはスケジューラーのgetDirectionメソッドを直接呼び出して上昇または下降の情報を取得し、渡されたパラメーターはそこにあります階、現在の走行方向、エレベータで実行中のリクエストディスパッチャは、エレベータの状態とディスパッチャ内の待ち行列に応じてエレベータの走行方向を判断し、エレベータに返します。方向は、前後に、すべてのエレベーター要求の実行を完了します。

  UMLダイアグラムは次のとおりです。

  スレッドが正しく終了する方法の設計方法は、終了信号が入力されると、最初に終了入力信号がスケジューラーに送信されます。つまり、スケジューラーの終了がtrueに設定され、入力スレッドが閉じられ、エレベータースレッドは実行ごとに終了します。次に、入力が完了したかどうか、ディスパッチャとエレベーターにまだ要求があるかどうかを確認します。要求がない場合は、エレベータースレッドが閉じられます。

  スレッド間の調整と同期の制御を図に示します。

  2. 2番目の宿題

  2番目の操作は、最初のエレベータを基準にしてエレベータの数を最大5つまで増やし、最初の入力エレベータの数に従ってエレベータの数を決定します。エレベータのタイプはまったく同じですが、エレベータは乗客定員には一定の制限があり、過負荷にすることはできないため、通常、2番目の操作は、1番目の操作に基づいて調整および増加するだけで済みます。

  私の設計戦略はメインスケジューラスレッドを追加することです。エレベーターの独自のスケジューラーに加えて、入力からのリクエストを継続的に受け取り、5つのエレベーターのスケジューラーの1つを割り当てることを決定します。私はもっ​​と良いマルチエレベータースケジューリングアルゴリズムを考えることができなかったので、運命を直接追跡し、乱数を使用して割り当てるエレベーターを決定し、エレベーターの独自のスケジューラーにそれを処理させました。

  エレベータースレッドの数を設定する方法については、実際の状況に応じて、エレベーターが消えたり、薄い空気から見えなくなったりする可能性があるため、プログラムの最初に5つのエレベーターが作成されましたが、どちらを使用するかは、入力したエレベーターの数によって異なります複数のエレベーターがあり、使用されていないマルチエレベータースレッドをシャットダウンして、アイドルランニングによるCPU時間の消費を防ぎます。

  UML图:

  3番目の宿題(より細かい):

  3回目の運転は一気に複雑化しますが、運転中にエレベータの台数を増やしたり、エレベータの種類を変えたり、運行時間、乗客数、呼び床などを変えたりしています。運用の難易度は一気に上がりましたが、じっくり考えた結果、運用の難易度はさほど高くありません。エレベーターの数は増やすことはできますが、最大数はまだ6台しかないので、現状ではプログラム1で当初は6基のエレベータが設置されていたが、他の3基は型式・名称の初期化が行われていなかったため、1階で停止した。エレベータを増設するためのフォローアップ入力を追加すると、エレベータの型式・名称が設定されて使用された。 3回目の全体的なフレームワークは、メインスケジューラとエレベーターの独自のスケジューラを使用する2番目のジョブと同様ですが、メインスケジューラはリクエストを送信する独自​​のスケジューラではなく、既存のスケジューラによるものです。実行できるエレベーターのタイプと要求によって割り当てが決まります。

  エレベーターには呼び出し可能なフロアが異なるため、入力クラスでは、転送する必要のあるすべての入力リクエストを2つの部分に分割し、それらをメインスケジューラに個別に渡します。分割戦略は半動的ですタイプの分割は、目的階と開始階によって決定され、通過する階はできるだけ少なく決定されます。もちろん、分割リクエストを直接メインスケジューラに渡して実行することはできません。それ以外の場合は、タイミングの問題により2つ発生します。同じ人が同時に異なるエレベーターを利用するので、メインディスパッチャーのキューを2つの部分に分けました。1つはエレベーターがキューに入るとすぐにエレベーターに配信できるキューで、もう1つは分割されたセカンダリキューです。スプリットキューは、スプリット前のリクエストが完了したかどうかに応じて実行できるかどうかを決定する必要があります。ここでは、各エレベータの専用スケジューラで直接エレベータの外に出ているかどうかの配列を示します。エレベータの乗客が出たらエレベーターの場合、対応するIDの配列値を1に設定できます。メインスケジューラの分割後、キューは配列値が1かどうかを判断してから、実行中かどうかを確認します。1の場合は、実行のためにエレベーターに配信できます。

  同じ種類のエレベータリクエストが割り当てられているエレベータについては、2番目のジョブに従ってランダム割り当て方法を使用し、対応するアイドルエレベータのタイプからランダムにエレベータ配信リクエストを選択します。乗客の負荷、実行時間などについては、直接エレベータークラスとディスパッチャークラスで拡張できます。

  UML图:

  

2.バグ分析

1.自分でデバッグする

  驚くべきことに、3つの割り当ての中間テストではWRONG ANSWERは表示されませんでした。ほとんどの発生はCTLEとRTLEであり、これら2つは基本的に同時に表示されました。CTLEの表示は多くの場合新しい機能です。暴力的なポーリングに似た構造を不可解に使用した場合、一度出現すると、それは待機、通知、およびスリープの操作でした。RTLEは、プログラムが正常に終了しなかったか、デッドロックが発生したため、すべてのプログラムが待機状態になります。この解決策は、終了変数の値とスレッドの安全性を綿密にチェックすることです。デッドロックの解決策は、直接それを排除し、他の方法を使用して同じ目的を達成することです。

  もちろん、最も悲しいことは、2回目の宿題が2〜3時間で完了し、中間テストに直接合格し、自信を持って直接合格したということです。強力なテストが乗客数に組み込まれるとは思いませんでした。制限があるのは、コードの2つのブランチのうち前のブランチだけを処理して、オーバーロードされているかどうかを判断し、もう1つのブランチが処理を忘れたためにプログラムがwaになったためです。

  RTLEの分析では、IDEA独自のTHREAD分析とJPROFILEを使用して操作を共同で判断します。実行中のプロセスとマルチスレッド間の調整と待機および実行の関係を直接確認できます。

2.他人をハックする

  WRONG ANSWERの構築ではデータをランダムに生成する方法を使用でき、WRONG ANSWERの発生はまれである可能性があるため、ほとんどの人のエラーはRTLEとCTLEで発生する可能性が高いため、非常に再現性の高いセットをいくつか作成しましたデータは非常に実行可能であり、1種類のエレベーターのみを使用し、それらはすべて同じルート上にあるため、スレッド安全でないプログラムでエラーが発生する可能性があります。

 

3.まとめと経験

  3つのエレベーター操作を完了した後、ため息をつくしかありません。最後に、最初のユニットの操作のように何度もリファクタリングする必要はありません。関数の反復を追加することは、はるかに簡単です。反復を達成するためにクラスを追加してコードを変更するだけです。目的。

  そして、マルチスレッドについての私の理解は常に深まっています。スレッドの安全性は特に重要です。それに対処しないと、不気味なイベントが発生し、プログラムとスレッドが正常に終了しない可能性があります。もちろん、Javaのデザインパターンも私は常に自分の練習とプログラミングを経験し、習得してきましたが、最後に最も重要なことは、デッドロックの大きな落とし穴を回避する方法を学び、私を待つ必要がなくなり、あなたを待つことです。

 

おすすめ

転載: www.cnblogs.com/b-two-w/p/12718794.html