視覚的に非スレッドセーフなデータ収集とをつかんで発生する可能性があり、消費者のモデルの製造工程中に問題を表現するために私たちは、4つのクラスに書かれている生産者、消費者、株式、およびメインスレッド関数呼び出しになりますソリューション。
ために生産者と消費者がスレッドを達成するためにしながら、我々は2社の消費者の株式は、共通リソースへのスナッチで、プロデューサーがあることを前提としています。
証券取引にのみ表示されて資源を奪うためにのみ対象となり、そのインベントリオブジェクトがユニークであるようにするために、我々は、シングルトンを達成し、コンストラクタのパラメータの生産者と消費者によって初期化するために2つのメソッドを使用することができます。
この例では、コンストラクタ、コードだけでなく、実施形態の単一モードを使用して書かれたコメントを使用する方法です。
シンプルな生産消費者のモデルを作成し、その動作結果を参照してください。
-
在庫カテゴリ:
パッケージproducterac、 輸入はjava.util.ArrayListの; パブリック クラス倉庫{ // の店舗アレイスレッドセーフなコレクション 専用のArrayList <文字列>一覧= 新しい新しいのArrayList <文字列> (); / * * //生産例のシングルモードを作成します同一の対象株式に動作する消費者 *専用倉庫は、(){} * //目標在庫確立するためにのみ初期化時に静的オブジェクトを作成 *プライベート新しい新しい静的倉庫ウェアハウスWH =を(); * * //方法を設定します静的には、インベントリオブジェクトの場合には、ので、新しいものではありません * //我々が直接クラス名を通じて静的メソッドを呼び出すことにより、静的メソッドを設定することができ 、倉庫のpublic staticのgetInstance(*){ *リターンWH; *} * / // プロデューサ倉庫操作方法書き込み 公開 無効追加の(){ IF(はlist.size()<20である){ List.add( "データ" ); } 他{ // データの直後に戻るに十分な、記憶されない運転データ記憶されている リターン; } } // 消費者は、操作倉庫オペレーション書き込み 公共 ボイドGETを(){ // コレクションだけでなく、データを削除できるかどうかを判断 // 裁判官はクロスボーダーのセットにならない場合は IF(はlist.size()> 0 ){ list.remove( 0 ) ; } 他{ リターン; } } }
- プロデューサーのカテゴリ:
以下のためのパッケージ変更producterac; パブリック クラス Producter 拡張スレッド{ プライベート文字列はpName; // 私たちは、株価操作と生産者と消費者を作りたいオブジェクト // にも在庫がオブジェクトを作成するために、シングルトンパターンを使用することができます プライベート倉庫WH、 公共Producter(文字列はpNameを、 WH倉庫){ この .pName = はpName; この .wh = WH; } // 実行オーバーライドメソッド 公共 ボイドラン(){ ながら(真の){ wh.add(); のSystem.out.println( "プロデューサー" +はpName +「貨物を追加します」); 試み{ // スレッドが待機を行いながら のThread.sleep(200で); } キャッチ{(InterruptedExceptionあるE) // TODO自動生成されたブロックキャッチ e.printStackTrace(); } } } }
- 消費者のカテゴリ:
以下のためのパッケージ変更producterac; パブリック クラスの消費者拡張スレッド{ プライベート文字列CNAME; // インベントリオブジェクトを取得する / * プライベート倉庫WH = WareHouse.getInstance(); * / // 私たちは、株価操作と生産者と消費者を作りたいオブジェクト // また、在庫シングルトンを作成するために使用することができるオブジェクト のプライベート倉庫WHを、 公共消費者(文字列CNAME、倉庫WH){ この .cName = CNAME; この .wh = WHは; } // runメソッドオーバーライド 公共 ボイドラン(){ しばらく(真){ wh.get(); のSystem.out.println( "消費者" + CNAME + "は、貨物を取った" ); 試み{ //はながらスレッドが待機を行う のThread.sleep(200で); } キャッチ(InterruptedExceptionあるE)を{ / / TODO自動生成されたブロックキャッチ e.printStackTraceを(); } } } }
- 主な機能カテゴリ:
パッケージproducterac。 パブリック クラスメイン{ 公共 静的 ボイドメイン(文字列[]引数){ 倉庫WH = 新しい倉庫()。 Producter P1 = 新 Producter( "1" 、WH); 消費者C1 = 新しい消費者( "1" 、WH); 消費者C2 = 新しい消費者( "2" 、WH); p1.start(); c1.start(); c2.start(); } }
結果の一部:
私たちは、の出現を参照 java.lang.ArrayIndexOutOfBoundsException 例外があるので、国境を越えた消費者のコレクションは、品物を奪うために時間を取得できませんでした示し、異常を。
でも、私たちの在庫get()メソッドでは、コレクションが空であるかどうかを判断するために、まだ例外がありました。同時に2つのスレッド内のオブジェクトにアクセスする際、裁判官だけで、スレッド1のコレクションは循環が空で入力していないが、最初にも、スレッド2 get()メソッドを品物を奪うない場合ず終了している場合があるためでありますスレッド1は、貨物の最後の一歩を踏み出した、と1が商品のコレクションを撮りたかったスレッドがなくなったときに、異常が、この場合に発生します。
そして、これは私たちがインベントリオブジェクトのスレッドロックを使用することができ、非セキュリティ問題の資源を奪うためのスレッドをもたらした同期の在庫への消費者のアクセスは、他の消費者をオブジェクト際にクロスボーダーの問題のセットを解決するためのインベントリオブジェクトにアクセスできないように、ロックアップを、スレッドセーフ。
- 変更されたストック・クラス(シンクロナイズド修飾子を(追加)と()メソッドを取得追加):
// プロデューサ倉庫操作方法書き込み 公的に 同期 ボイド追加を(){ IF(20 <さはlist.size(){) List.add(「データ」); } 他{ // 、データを十分に格納された後に直接戻りません操作と走行データ記憶の リターン; } } // 書き込み消費者動作倉庫操作 パブリック 同期 ボイドGET(){ // コレクションならびにデータを除去することができるかどうかを決定する // 裁判官はクロスボーダーのセットをもたらさない場合 IF(はlist.size ()> 0 ){ list.remove( 0 ); } そう{ 返します。 } }
棚卸方法を変更した後、同期修飾子はあきらめていません使用しています!
また、()を待つように変更リターンで書かれた消費者のモデルの生産を待つ待機()メソッドのスレッドに置き換え返すことができます。
- 変更されたストック・クラス:
// メソッドプロデューサが操作倉庫ライト 公衆に 同期 ボイド)を追加し({ IF(はlist.size()<20 ){ List.add(「データ」); } 他{ 試み{ // これはこれをアクセスすることを意味スレッド待機在庫オブジェクト、オブジェクトが在庫ない待つ この.WAITを(); } キャッチ(InterruptedExceptionあるE){ // TODO自動生成キャッチブロック e.printStackTrace(); } } } // 書き込み消費者動作倉庫操作 公衆 同期 のボイド{GET() // データセットが存在するか否かを判定するが除去されてもよい // 決意結果が境界を設定されていない場合 IF(はlist.size()> 0 ){ list.remove( 0 ); } 他{ 試み{ // このこのインベントリ対象スレッド待ちへのアクセスは、オブジェクトが在庫待たないことを意味する 。この; .WAIT() } キャッチ(InterruptedExceptionあるE){ // TODO自動生成されたブロックキャッチ e.printStackTrace(); } } }
結果:
我々は最終的にすべてのスレッドが実行の最後のスレッドに実行し、待機待ち状態になっていないことがわかります。だから我々は、他のスレッドは、システムの稼働を維持するために、目を覚ますしていきます際つのスレッドを待つ必要があります。
スレッドが使用できるウェイク通知/のnotifyAll()メソッドを。
- 再び株式クラスを変更:
// メソッドがプロデューサー倉庫操作書き込む 公共 同期 のボイド追加(){ IF(はlist.size()<20 ){ list.add(「データ」); } 他{ 試み{ // 我々が知らないので、どのスレッド消費者のスレッドので、私たちはすべてのスレッドをウェイクアップする必要があり 、この; .notifyAll() // この本は、インベントリへのアクセスは、スレッド待ちオブジェクト待つ在庫対象ではないことを意味し 、この.WAITを(); } キャッチ(例外:InterruptedException Eを){ / / TODO自動生成されたブロックキャッチ e.printStackTraceを(); } } } // 書き込み消費者動作倉庫操作 パブリック 同期 ボイドGET(){ // コレクションかどうかを決定するだけでなく、データを除去することができる // 裁判官は、クロスボーダーのセットをもたらさない場合 IF(はlist.size()> 0 ){ リスト。削除( 0 ); } 他{ 試み{ // 私たちは生産者スレッドであるスレッドを知らないので、我々はすべてのスレッドウェイクアップする必要があるため 、この.notifyAllを(); // これは、このインベントリオブジェクトのスレッド待ちへのアクセスを意味し、待機与えない在庫 本)(.WAITを; } キャッチ(InterruptedExceptionあるE){ //TODO自動生成されたcatchブロックの e.printStackTrace(); } } }
成功を実行しています!説明この時間は、私たちは本当に消費者モデルの簡単な製造を実現しました。
添付:同期修飾農産物の消費者モデルが追加()とget()メソッドが削除された場合、次のエラーが発生します完了します。
同期修飾子を除去した後、それが発生したjava.lang.IllegalMonitorStateExceptionのスレッド1は、その時間の待機()メソッドを実行する他に入ったときので、例外を、スレッド2はまた、インベントリオブジェクトを入力したような待機()メソッドが実際に実行された場合、そのこの問題が発生した際に待ち時間は、スレッド1スレッド2でなく、ときに異常が発生します。