Javaのマルチスレッドの学習(5) - 通知メカニズムを待ちます

実現の通知メカニズムを待ち

アクション待ちの方法()は、待機()メソッドは、メソッドオブジェクトクラス、「実行前キュー」への現在のスレッドであり、(待機)位置でコード実行を停止し、待機するように現在のスレッドでありますまでに通知または割り込みが発生します。のみ高速同期に使用される同期方法または待機()メソッドは、実行待ち()の後に、現在のスレッドがロックを解除します。

オブジェクトメソッド通知()メソッドまたは同期はまた、オブジェクト・レベルのロックを取得する必要があり呼び出す前に、高速同期を呼び出します。スレッドプランナーによるスレッドを待っている複数のスレッドが存在する場合、このオブジェクトのロックを待機している他のスレッドに通知するために使用される方法は、ランダムにそれが通知通知を発行し、待機状態を選択したので、彼は、オブジェクトのロックを取得するために待機します。

通知()を実行した後、現在のスレッドは、直ちに彼らがロックを取得する前に、コードの出口同期ブロックは、スレッドで待機状態のスレッドがロックを解除し、ロックを解除しません。最初の取得は、オブジェクトのロック待ちスレッドが実行のロックの端を解放すると、オブジェクトが再び通知されない場合は、他のスレッドは、このオブジェクトが通知したりのnotifyAll発するまで状態がまだ待機をブロックされます待ちます。

public class MyWait {

    private final Object lock;

    MyWait(Object lock){
        this.lock=lock;
    }

    public void waitTest(){
        try {
            synchronized (lock){
                System.out.println("开始 wait time = " + System.currentTimeMillis());
                lock.wait();
                System.out.println("结束 wait time = " + System.currentTimeMillis());
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
复制代码
public class MyNotify {
    private final Object lock;

    MyNotify(Object lock){
        this.lock=lock;
    }

    public void notifyTest(){
        synchronized (lock){
            System.out.println("开始 notify time = " + System.currentTimeMillis());
            lock.notify();
            System.out.println("结束 notify time = " + System.currentTimeMillis());
        }
    }

}
复制代码
public class Main {

    public static void main(String[] args){
        try {
            Object lock = new Object();
            MyWait myWait = new MyWait(lock);
            new Thread(() -> myWait.waitTest()).start();
            Thread.sleep(3000);
            MyNotify myNotify = new MyNotify(lock);
            new Thread(() -> myNotify.notifyTest()).start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
复制代码
开始 wait time = 1552812964325
开始 notify time = 1552812967328
结束 notify time = 1552812967328
结束 wait time = 1552812967328
复制代码

コンテンツ出力から分かるように通知する方法は、3秒間行われ、方法は、方法を通知待機実行の終了後に行われます。

関連するメソッド

  • 待って():スレッドが実行状態から撤退、その後、共有リソースのロックを解除するために、このメソッドを呼び出して、それらが再び目覚めたまで、待ちキューに入ります。
  • 待つ(ロング):何の通知タイムアウトが返されない場合はタイムアウトはいくつかの時間を待って、ここではミリ秒単位の時間のパラメータである、つまり、nはミリ秒まで待機します。
  • ランダムウェイクアップ同じ共有リソース「スレッド」を待っているキュー内で待機して、スレッドは終了し、キューを待って、実行可能、つまり、通知()メソッドのみ通知:()通知「のスレッドを。」
  • notifyAll():すべての「すべてのスレッドが」実行可能な同じ共有リソース待ちキューを出るのを待っているキューで待機しています。このとき、最初に実行優先順位が最も高いスレッドが、それはまた、実装JVM仮想マシンに応じて、ランダムに実行することができます。

スレッドの基本的な状態

https://blog.csdn.net/qq_34337272/article/details/79690279を得て転載

  1. 新(新新):新しいスレッドオブジェクトを作成します。

  2. ラン(Runnableを):(例えばメインスレッドなど)スレッドオブジェクトを作成した後、他のスレッドは、オブジェクトのstart()メソッドを呼び出します。スレッドの状態は、CPUを使用する権利を取得し、スレッドのスケジューリングを選択されるのを待って、プール内の実行可能スレッドに位置しています。

  3. 運転(ランニング):(Runnableを)実行可能なプログラムコードの実行、CPUタイムスライス(タイムスライス)のスレッドを得ました。

  4. (ブロック)をブロッキング:ブロッキング状態は一時的に実行を停止し、CPUのタイムスライスの外にさせているCPUを使用する権利を放棄するためにいくつかの理由のためのスレッドです。スレッドが実行可能(実行可能)状態になるまで、あなたは再び(ランニング)の状態を実行するために、CPUのタイムスライスを取得する機会を持っています。三つのカテゴリーの閉塞の場合:

。(A)のブロックを待ち:実行のスレッドが(ランニング)()メソッドを実行しているo.wait、JVMはで待機キュー(waittingキュー)に通すます。

(B)同期ブロッキング:スレッドが実行(実行)同期ロックオブジェクトを取得する際、同期ロックが別のスレッドによって占有されている場合、JVMは、中(プールをロック)スレッドプールにロックされます。

(三). **其他阻塞**: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
复制代码
  1. 死(死):スレッドの実行()、main()メソッドが実行を終了し、または異常なまでrun()メソッド、ライフサイクルの糸端から撤退しました。死のスレッドが再び復活することはできません。

コードのこのセクションではGitHubの

結合を使用

多くの場合、メインスレッドが作成すると、オペレータは、スレッドの多くがかかっている場合、プロモータースレッドは、メインスレッドは、多くの場合、子スレッドが終了する前に出会いの終わりです。メインスレッドは、子スレッドの実行を待つの後、最後に完了している場合は、我々は()関数はスレッドオブジェクトが破棄される待っている参加、join()メソッドを使用する必要があります。

()メソッドだけでなく、参加(長いミリ秒)を提供するに参加するスレッドクラスまた、2つのタイムアウト特性を有する(長いミリ秒、nanos値をint)を参加します。これらの2つの方法のタイムアウトは、スレッドのスレッドが指定されたタイムアウト期間内に終了しない場合、それはタイムアウトメソッドから返されると述べました。

public class Main {

    public static void main(String[] args) throws InterruptedException{
        Thread thread = new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName()+"正在执行");
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }, "线程1");
        thread.start();
        thread.join();
        System.out.println("等待"+thread.getName()+"执行完");
    }
}
// 输出
线程1正在执行
等待线程1执行完
复制代码

差分ジェイン(長い)スリープ(ロング)の

この方法は、(長い)関数への参加(ロング)メソッド待機内部に実装さ(long)メソッドを使用するので、参加されたロック機能を解除します。ロックを解除していない二つのスリープ(ロング)。

ThreadLocalの使用

変数の値は、共有のパブリック静的変数の形で使用することができ、すべてのスレッドが同じパブリック静的変数を使用しますが、各スレッドを達成する必要がある場合は、独自のシェアにThreadLocal変数を解決するために使用することができました。

ThreadLocalの関連するメソッド:

  • ()取得:このスレッドローカル変数の現行スレッドのコピーの値を返します。
  • セット(T値):指定された値に、このスレッドローカル変数の現在のスレッドのコピー。
  • ()削除:現在のスレッドの、このスレッドローカル値を削除します。
  • initialValue():現在のスレッドのために、このスレッドローカル変数に戻るには、「初期値」。

スレッド間の変数の単離

public class ThreadLocalTeat {
    public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException{
        int count = 30;
        String name = "Thread-";
        for (int i=0; i<count; i++){
            Thread thread = new Thread(() -> {
                threadLocal.set(Thread.currentThread().getName());
                System.out.println(threadLocal.get());
            }, name+i);
            thread.start();
        }
        Thread.sleep(20000);
    }
}
// 输出
Thread-0
Thread-4
Thread-3
Thread-6
Thread-2
Thread-1
Thread-7
。。。
复制代码

使用InheritableThreadLocal

使用クラスInheritableThreadLocalは、子スレッドで親スレッド継承した値を得ることができます。

public class InheritableThreadLocalTest extends InheritableThreadLocal {
    @Override
    protected Object childValue(Object parentValue) {
        return super.childValue(parentValue);
    }

    @Override
    protected Object initialValue() {
        return System.currentTimeMillis();
    }
}
复制代码
 * @date 2019/6/18 8:28
 * @description
 */
public class InheritableTeat {
    static public class Inner{
        public static InheritableThreadLocalTest threadLocalTest = new InheritableThreadLocalTest();
    }


    public static void main(String[] args) throws InterruptedException{
        for (int i = 0; i<3; i++){
            System.out.println("在main线程中获取值:"+ Inner.threadLocalTest.get());
        }

                for (int i=0; i<3; i++){
                    new Thread(() -> {
                        System.out.println("在"+Thread.currentThread().getName()+"中获取值:"+ Inner.threadLocalTest.get());
            }, "Thread-"+i).start();
        }
        Thread.sleep(1000);

    }

}
// 输出
在main线程中获取值:1560818029616
在main线程中获取值:1560818029616
在main线程中获取值:1560818029616
在Thread-1中获取值:1560818029616
在Thread-2中获取值:1560818029616
在Thread-0中获取值:1560818029616
复制代码

使用の際に注意すべきInheritableThreadLocalクラスの事:変更を加えるInheritableThreadLocal値でメインスレッドの値を得るための子スレッド場合、子スレッドが古い値に運ばれました。


国民の関心番号へようこそ。

いいえマイクロチャネル公共ません

おすすめ

転載: juejin.im/post/5d783fa1e51d4561ae4da6ab