Javaのマルチスレッドプログラミング - (4) - 導入およびスレッド間通信機構の使用

前:

Javaのマルチスレッドプログラミング - (1) - 同期スレッドセーフとロックコンセプト

Javaのマルチスレッドプログラミング - (2) - リエントラントロック、および同期の他の基本的な特性

Javaのマルチスレッドプログラミング - (3) - 導入およびスレッドローカルのThreadLocalの使用

スレッド間通信のはじめに
私たちは、スレッドがシステムの独立した個人を動作していることを知っているが、これだけでは、個人間の治療の特別な種類のものですが、それ全体作る、スレッド間で交換やコミュニケーションが存在しない、彼は別のものです個人は、十分ではない強力な全体的な強い相互作用を形成しました。

各CPUの使用率とスレッド間の相互協力のメカニズムを改善するために、Javaはスレッド間通信の実装である:インター待機は/スレッド間通信を通知し、以下は、このスレッド間の通信メカニズムについて一緒に学びます。

スレッド間通信を実現するためのメカニズムを通知/待って使用しないでください
どのように我々は下を達成するためのコードの一部を見て、二つのスレッド間の通信を実現することはリストに2つのスレッドを満たすことであることを、我々は以下のメカニズムの使用を導入する必要がない場合をデータ:

マイリストコード:

パブリッククラスMYLIST {

    プライベートリストリスト=新しいArrayListを();

    追加VOIDパブリック(){
        List.add( "I要素");
    }

    公共int型のサイズ(){
        リターンはlist.size()。
    }

}

スレッド:

パブリッククラススレッドAは{スレッドを拡張します

    プライベートMYLISTリスト。

    公共スレッドA(MYLISTリスト){
        スーパー();
        this.list =リスト。
    }

    @Override
    ます。public void実行(){
        {みてください
            (int型私= 0;私は<10; I ++){のために
                list.add();
                System.out.println( "添加了" +(I + 1)+ "个元素")。
                Thread.sleep(1000);
            }
        }キャッチ(InterruptedExceptionある電子){
            e.printStackTrace();
        }
    }

线程B:

パブリッククラスThreadBは{スレッドを拡張します

    プライベートMYLISTリスト。

    公共ThreadB(MYLISTリスト){
        スーパー();
        this.list =リスト。
    }

    @Override
    公共ボイドRUN(){
        試み{
            ながら、(真の){
                IF(はlist.size()== 5){
                    System.out.printlnは( "引き出される== 5、Bのスレッド!");
                    新しいスローは新しいですInterruptedExceptionある();
                }
            }
        }キャッチ(InterruptedExceptionあるE){
            e.printStackTrace();
        }
    }
}

テストクラステスト:

パブリッククラスTest {

    パブリック静的無効メイン(文字列[] args){
        MYLISTます。myList =新しいMYLIST()。

        スレッドAのA =新しいスレッドA(はmyList);
        a.setName( "A")。
        a.start();

        B =新しい新規かつThreadBそのThreadB(ます。myList);
        b.setName( "B");
        b.start();
    }
}

結果:

要素を追加した
二つの要素が追加されます
三つの要素を追加した
4番目の要素を追加するために
5つの要素の追加
== 5を引き抜くことが、Bスレッドを!
java.lang.InterruptedException
    text.ThreadB.run AT(ThreadB.java:20)は
6つの要素追加
要素7を追加する
8つの要素が追加
9つの要素を追加し
10個の要素が追加

リストのセットいることがわかります5時間スレッドBが終了するためのデータ、二つのスレッド間の通信を可能にするが、我々のコードは、スレッドBは、明らかに、実行を終了するためにのみ5の長さまでしばらく(真)ループを実施しているものの方法は非常に資源集約的です。だから、我々は上記の動作を回避するための仕組みが必要でなく、複数のスレッド間の通信を可能にし、これが次のステップは学ぶことですされて、「待っ/通知スレッド間通信を。」

何を待っている/通知メカニズムの
理由は、我々は我々が発表放送されます達するときに、ドアの後、ビジネス、チケット番号を行うために銀行に行く、これは非常に現実的なシナリオであるようにビジネスを行うと同じように、非常に簡単です、我々は上のチケット番号を取りました私たちは、チケット番号が通知を放送される時間が来たように事務員として、待つ必要があります。

Javaの待ち/通知機構を実装
方法に対応するJava待機/通知(待機あり)/()通知以下に示すように、これらの2つの方法は、スーパークラスオブジェクトです。

理由は、スーパークラスオブジェクトのメソッドである、我々は簡単に理解することができます。私たちは、任意のオブジェクト上のいくつかの記事をロックとして使用することができます知っている、と待機()/通知は、()ロックによって呼び出され、この種の考えは理解することができますここの場所に巧妙なデザインです。

、waitメソッド

エフェクト(1)メソッド待ち()は、「実行前キュー」にねじ込まれる現在待っているコードの実行スレッドにある、と通知されるまで待機()がストップコードに配置されて実行されますまたは割り込みが発生します。

(2)呼び出しは(待つようにする前に)、ロックオブジェクトレベルを取得する必要がありますスレッドが、これが唯一の同期ブロックの同期方法または方法でwait()を呼び出すことができる非常に重要な場所、私たちはそれを忘れて何回も、です。

(3)また、待ち時間は、()()メソッドを待つために実行した後、つまり、ロックを解除することであることに注意して、現在のスレッドのロックを解除、待機()メソッド、スレッドと他のスレッドから現在に戻り、ロックを取り戻すために競います。

二つには、メソッドに通知します

(1)及び待機()メソッドのように、通知()メソッドを呼び出す前に、スレッドは、オブジェクトのオブジェクト・レベルのロックを獲得しなければならない、すなわち、同期ブロックまたは同期メソッドで呼び出されるべきです。

その通知のスレッドが通知前記スレッドスケジューリングランダムに選択された待機状態形態により、待機中の複数のスレッドが存在する場合(2)このメソッドは、他のスレッドがこのロックオブジェクトを待ってもよいことを通知するために使用されそれは、オブジェクトのオブジェクトのロックを取得するためと待ちます。

(3)メソッドを通知し実行した後、現在のスレッドはすぐにその所有しているオブジェクトのロックを解除しませんが、実行後のオブジェクトのロックを解除し、ことに留意すべきである、スレッドはロックオブジェクトすぐに通知されません。彼らは、オブジェクトのロックを取得することができます前に、しかし、この方法を通知待って実行した後、オブジェクトのロックが解除されます。

(3)のnotifyAll()は、すべての待機中のスレッドがすべて実行可能、待機状態から出るのと同じリソースを共有して、オブジェクトのロックを再競う通知します。

三、()/通知()メソッドを待ちます

(1)それらはオブジェクトのオブジェクトのロックを獲得する必要があるため、併用同期キーワードのセットについて)(通知/)(待ちます。

(2)メソッドを待ってロックが解除されていない通知、ロックを解除することです。

スレッド以下四つの状態(3):

スレッドが通知/待つ間のコードのコミュニケーションをサンプル
変換コードが待ちに使用されていない/次のように通知:

マイリストコード:

パブリッククラスMYLIST {

    プライベート静的リスト一覧=新しいArrayListを();

    静的ボイドパブリック追加(){
        List.add( "I素子");
    }

    パブリックstatic int型のサイズ(){
        リターンはlist.size()。
    }
}

线程A:

パブリッククラススレッドAは{スレッドを拡張します

    プライベートオブジェクトのロック。

    パブリックスレッドA(オブジェクトロック){
        スーパー()。
        this.lock =ロック。
    }

    @Override
    ます。public void実行(){
        {しようと
            {(ロック)同期
                の場合(MyList.size()= 5!){
                    System.out.printlnは( "待っ始まる" +のSystem.currentTimeMillis());
                    lock.wait();
                    System.out.println( "終了を待つ" +のSystem.currentTimeMillis());
                }
            }
        }キャッチ(InterruptedExceptionある電子){
            e.printStackTrace();
        }
    }
}

线程B:

パブリッククラスThreadBは{スレッドを拡張します

    プライベートオブジェクトのロック。

    公共ThreadB(オブジェクトロック){
        スーパー()。
        this.lock =ロック。
    }

    @Override
    ます。public void RUN(){
        試み{
            同期(ロック){
                (int型I = 0;私は10に<;私は++)について{
                    MyList.add();
                    IF(。MyList.size()== 5){
                        lock.notify ();
                        のSystem.out.println( "既に通知された!");
                    }
                    のSystem.out.printlnは(+(I + 1)+ "追加" " 要素!");
                    のThread.sleep(1000);
                }
            }
        }キャッチ(InterruptedExceptionあるE){
            e.printStackTrace();
        }
    }
}

テストコード:

パブリッククラスを実行します{

    パブリック静的無効メイン(文字列[] args){
        試み{
            オブジェクトロックは=新しいオブジェクト();
            スレッドAのA =新しいスレッドA(ロック)。
            a.start();
            Thread.sleep(50)。
            ThreadB B =新しいThreadB(ロック)。
            b.start();
        }キャッチ(InterruptedExceptionある電子){
            e.printStackTrace();
        }
    }
}

运行结果。

1507634541467が始まるまで待機
要素を追加しました!
2つの要素を追加します!
三つの要素を追加しました!
4つの要素が追加!
通知をしました!
5つの追加要素が!
6つの要素を追加しました!
7つの要素を追加しました!
8つの要素を追加します!
9つの要素を追加しました!
10個の要素を追加!
待機終了1507634551563

例上記の単に通知メカニズムを待って達成されました、我々はまた、しかし唯一のオブジェクトロックスレッドB通知5番目の要素を取得した後、参照、および達成も説明することができる実行スレッドBが、スレッド、メソッドがロックを解除することで待機し、方法はない通知することができますロックを解除します。

別の場合:使用して、待機/キューのブロッキング通知アナログBlockingQueueの
BlockingQueueのキューがブロックされ、我々が実装する必要がでブロックされ、データを取得され、次のように、デザインのアイデアは、次のとおりです。

(1)最大キュー長が5であり、初期化 
、時間の(2)新規追加が5つの待機挿入である場合は、長さが5であるか否かを判断する; 
(3)必要な場合に消費要素、0の場合、0か否かを判断します消費者を待っています。

次のようにコードは次のとおりです。

パブリッククラスMYQUEUE {

    // 1、インストールするための要素のセットが必要
    民間最終のLinkedList <オブジェクト> =新しい新しいリストLinkedListは<>を();
    // 2、カウンタ必要
    のAtomicIntegerののAtomicInteger新しい新しいCOUNT =(0)の民間最終;
    // 3、指定上下の
    民間最終maxSizeのINT = 5;
    民間最終に、minSize INT = 0。

    5 //初期化ロックオブジェクト
    民間最終オブジェクトロック=新しいオブジェクト( );

    / **
     * PUTメソッド
     * /
    公共ボイドPUT(オブジェクトobj){
        同期(ロック){
            //最大まで、追加入力することはできません
            しばらく(count.get()== maxSizeの){
                試み{
                    lock.wait();
                キャッチ}(InterruptedExceptionあるE){
                    e.printStackTrace();
                }
            }
            List.add(OBJ); //添加元素
            count.getAndIncrement(); //カウンタがインクリメントされる
            ( "要素" + OBJ +「するSystem.out.printlnであります追加「);
            ()lock.notify; //別の方法を阻止するスレッドに通知
        }
    }

    / **
     * GETメソッド
     * /
    パブリックオブジェクトGET(){
        TEMPオブジェクト;
        同期(ロック){
            //最小値、消費のどの要素がするまで入力することはできませんがあり
            ながら、(count.get()==に、minSize){
                試み{
                    ロック。待機();
                }キャッチ(InterruptedExceptionあるE){
                    e.printStackTrace();
                }
            }
            count.getAndDecrement();
            TEMP = list.removeFirst();
            のSystem.out.println( "要素" + TEMP + "が消費されます") ;
            lock.notify();
        }
        戻りTEMP;
    }

    プライベートint型のサイズ(){
        リターンcount.get();
    }

    公共の静的な無効メイン(文字列[]引数)が例外をスロー{

        最終MYQUEUE MYQUEUE =新しいMYQUEUE()。
        initMyQueue(MYQUEUE)。

        スレッドT1 =新しいスレッド(() - > {
            myQueue.put( "H");
            myQueue.put( "I");
        }、 "T1")。

        スレッドT2 =新しいスレッド(() - > {
            {試みる
                のThread.sleep(2000);
                myQueue.get();
                のThread.sleep(2000);
                myQueue.get();
            }キャッチ(InterruptedExceptionある電子){
                e.printStackTrace( );
            }
        }、 "T2")。

        t1.start();
        Thread.sleep(1000);
        t2.start();

    }

    静的ボイドinitMyQueueプライベート(MYQUEUE MYQUEUE){
        myQueue.put( "A");
        myQueue.put( "B");
        myQueue.put( "C");
        myQueue.put( "D");
        myQueue.put( " E ");
        のSystem.out.println("要素の現在の数:「+ myQueue.size());
    }
}

結果:

 添加元素をれる 
 要素Bを添加する 
 元素Cが追加される 
 要素がD追加される 
 要素eを追加している 
現在の要素の数:5
 要素が消費者である 
 要素hが追加される 
 要素Bが消費される 
 iが追加された要素を 

補足事項
(1)(待機)、及び通知()メソッドを呼び出し前にシンクブロックまたは同期化方法、すなわちで呼び出される、スレッドがオブジェクトのロック・オブジェクト・レベルを取得しなければなりません。

(2)メソッドを待ってロックが解除されていない通知、ロックを解除することです。

(3)ウェイク状態を待っている各スレッドが待機通知ランダムであり、各のみウェイクアップ。

(4)それは競争再びオブジェクトロック、最初に実行される最高の優先順位のスレッドを取得するために状態を各スレッドを待つ待機ウェイクnotifAll。

(5)スレッドが待機()状態にあるときは、呼び出し元のスレッドオブジェクトの割り込み()メソッドは、異常InterruptedExceptionあるでしょう。

他の知識
(1)プロセス間通信:

導管(パイプ)、名前付きパイプ(名前付きパイプ)、信号量(semophore)、メッセージキュー(メッセージキュー)、信号(シグナル)、共有メモリ(共有メモリ)、ソケット(ソケット)。

(2)スレッド間通信範囲:

図1に示すように、ロック機構 
1.1ミューテックスは:排他的同時変更データ構造に予防する方法を提供します。 
1.2書き込みロック:読み取りは、同時に複数のスレッドがデータを共有することができ、かつ操作が相互に排他的である書きます。 
1.3条件変数:特定の条件がこれまでに真になるまであなたは、アトミックプロセスをブロックすることができます。

テストのための条件は行わミューテックスの保護下にあります。常にミューテックスと条件変数を一緒に使用します。

2、セマフォ機構:スレッド名前セマフォとセマフォ有名スレッド 
3、シグナリングメカニズム:プロセス間は、信号処理と同様です。

スレッド同期のためのスレッド間の通信の主な目的なので、そのようなプロセス間通信のためのデータの交換などいかなるスレッド通信メカニズムは存在しません。
--------------------- 
著者:徐ゲン 
出典:CSDN 
オリジナルます。https://blog.csdn.net/xlgen157387/article/details/78195817 
免責事項:この記事ブロガーのオリジナルの記事、複製など、ボーエンのリンクを添付してください!

おすすめ

転載: blog.csdn.net/hellozhxy/article/details/92786283