スレッドクラスのソースコードの分析

Threadは、インタビューでのマルチスレッドの問題にとって非常に重要なクラスです。Threadクラスの奇妙な点と、インタビュアーからのさまざまな難しい質問に答える方法を見てみましょう。

スレッドの使用

スレッド名

マルチスレッドを使用する場合、一般的に使用される方法は、シーン名、つまりsetName(String name)とgetName()を設定して表示することです。

デフォルトでは、メインスレッドの名前はmainであり、他のスレッドの名前はThread-xです。ここで、xはスレッドの数を表します。理由は工法により異なります

public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

内部でnextThreadNumメソッドを呼び出すinitメソッドを呼び出すことがわかります。このメソッドはスレッドセーフなメソッドであり、同時に変更できるのは1つのスレッドのみです。また、threadInitNumberは静的変数であり、クラス内のすべてのオブジェクトからアクセスできるため、各スレッドは、作成時に子スレッドのサフィックスとして直接+1されます。

スレッドの優先度

スレッドの優先度は、スレッドがCPUタイムスライスをプリエンプトする確率として理解できます。優先度が高いほど、取得の可能性が高くなりますが、高い優先度を最初に実行する必要があるという意味ではありません。

デフォルトの優先度は5、最大値は10、最小値は1です。

では、スレッドの実行順序を確認するにはどうすればよいでしょうか。

  • join()メソッドを使用できます

Thread.join()は、指定されたスレッドを現在のスレッドに結合し、交互に実行される2つのスレッドを順次実行スレッドにマージできます。たとえば、スレッドAのJoin()メソッドがスレッドBで呼び出され、スレッドAが実行を終了するまでスレッドBは実行を継続しません。

デーモンスレッド

デーモンスレッドは、その名前が非常に控えめです。デーモンスレッドは、他のスレッドにサービスを提供する優先度の低いスレッドです。他のスレッドが実行されると、JVMとともに終了します。ガベージコレクションスレッドは、一般的なデーモンスレッドです。

主な特徴

  • 他の非デーモンスレッドの実行が終了すると、仮想マシンが終了し、デーモンスレッドが停止します。
  • デーモンスレッドはサービススレッドであり、サービスオブジェクトなしで実行を継続する必要はありません。
  • デーモンスレッドはいつでもハングする可能性があるため、共有リソースにアクセスしないでください。
  • デーモンスレッドで生成された新しいスレッドもデーモンスレッドです

デーモンスレッドは、setDaemonによって設定できます。

public final void setDaemon(boolean on) {
    // 判断是否有权限
    checkAccess();
    // 判断是否活跃
    if (isAlive()) {
        throw new IllegalThreadStateException();
    }
    daemon = on;
}

ソースコードから、スレッドを開始する前にターゲットスレッドをデーモンスレッドとして設定する必要があることがわかります。そうしないと、エラーが報告されます。

start()とrun()の違い

これはよくある面接の質問ですが、混乱するのも非常に簡単です。

  • runメソッドで定義されているのは、スレッドによって実行されるタスクロジックであり、通常のメソッドと同じです。
  • startメソッドはスレッドを開始し、スレッドをNEW状態からRUNNABLEに変えてから、jvmがスレッドのrun()メソッドを呼び出してタスクを実行します。
  • startメソッドを複数回呼び出すことはできません。そうしないと、java.lang.IllegalStateExceptionがスローされ、run()メソッドは通常のメソッドであるため、複数回呼び出すことができます。

JVMはstartメソッドを実行し、別のスレッドはスレッド内のrunメソッドを実行します。これはマルチスレッドの役割を果たすことができます。スレッド内のrunメソッドが直接呼び出された場合、そのメソッドは影響を受けることなくメインスレッドに残ります。マルチスレッドの。

睡眠法

  • 指定されたミリ秒数の間スリープします。その間、ロックは解除されません。
  • パラメータが不正な場合は、IllegalArgumentExceptionをスローします
  • スリープ状態では、それに応じて信号を中断することができ、InterruptedExceptionがスローされます

スレッドを適切に停止する方法

最初に明確にする必要があるのは、stop()メソッドを使用しないことです。暴力的すぎます。スレッドが停止する前にデータを保存するロジックを処理するための十分な時間がスレッドに与えられていない場合、タスクが停止し、データが発生します。整合性の問題。

通常の状況では、割り込みメソッドはスレッドの停止を要求するために使用されます。停止よりもはるかに穏やかです。スレッドにシグナルを送信して終了するように指示するだけで、スレッドは停止方法と停止するかどうかを決定します。独自のビジネスロジックの停止によるものではありません。

割り込み方式には4つのポイントがあります

  • 自分自身に割り込むことしかできません。そうしないと、SecurityExceptionがスローされます。
  • スレッドがwait、sleep、join、およびその他のメソッドを呼び出してブロックすると、呼び出しの中断が無効になり、InterruptedExceptionがスローされます。
  • 上記の状況が発生しない場合、スレッドの中断ステータスが変更されます。
  • ハングアップしたスレッドを中断することは無効です。

さらに、Javaの割り込みに関連するメソッドはinterrupted()とisInterrupted()です。

  • isInterrupted()は、割り込みフラグビットを決定するために使用されます。呼び出しは現在のフラグビットに影響を与えません。
  • 割り込み()は割り込みフラグビットをクリアするために使用され、呼び出しはフラグビットをクリアします

降伏法

Threadのソースコードを見ると、yield()メソッドがローカルメソッドであることがわかります。CまたはC ++によって実現されます。不安定です。

現在のスレッドはyield()を呼び出して、他のスレッドによる実行にCPUを使用する権利を放棄しますが、CPUを最初に取得した人が最初に実行するため、放棄する保証はありません。

現在のスレッドはyield()メソッドを呼び出します。このメソッドは、状態をRUNNABLEからWAITINGに変更します。

結合メソッド

joinメソッドを呼び出すと、スレッドの実行が完了するのを待ってから他のスレッドを実行します。このメソッドを使用して、スレッドの整然とした実行を実装できます。

最下層は引き続きwait()メソッドを介して実装されます

現在のスレッドが終了すると、現在のインスタンスのnotifyAllメソッドが呼び出され、他のスレッドがウェイクアップされます。

joinメソッドを呼び出すと、現在のスレッドがRUNNABLE状態からWAITING状態に変更されます。

スレッド実際の戦闘ドリル

スレッドに名前を付ける

  • マルチスレッドを実現するためにRunnableを実装
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        //打印出当前线程的名字
        System.out.println(Thread.currentThread().getName());
    }
}
  • テスト
public class MyRunnableDemo {
    public static void main(String[] args) {
        // 创建MyRunnable类的对象
        MyRunnable my = new MyRunnable();
        // 使用带参构造方法给线程起名字
        Thread t1 = new Thread(my,"关注我");
        Thread t2 = new Thread(my,"冢狐");
        t1.start();
        t2.start();
        // 打印出当前线程的名字
        System.out.println(Thread.currentThread().getName());
    }
}
  • 結果

画像

デーモンスレッド

  • デーモンスレッドを設定します
public class MyRunnableDemo {
    public static void main(String[] args) {
        // 创建MyRunnable类的对象
        MyRunnable my = new MyRunnable();
        // 使用带参构造方法给线程起名字
        Thread t1 = new Thread(my,"关注我");
        Thread t2 = new Thread(my,"冢狐");
        //设置守护线程
        t2.setDaemon(true);
        t1.start();
        t2.start();
        // 打印出当前线程的名字
        System.out.println(Thread.currentThread().getName());
    }
}
  • 結果

画像

スレッド1とメインスレッドが実行された後、デーモンスレッドは実行されないため、開始する前にデーモンスレッドを設定する必要があります

スレッドストップ

public class Main {
    public static void main(String[] args) {
        Main main=new Main();
        //创建线程并启动
        Thread t=new Thread(main.runnable);
        System.out.println("This is main");
        t.start();
        try {
            // 在main线程睡个三秒钟
            Thread.sleep(3000);
        }catch (InterruptedException e){
            System.out.println("In main");
            e.printStackTrace();
        }
        // 设置中断
        t.interrupt();
    }
    Runnable runnable=()->{
        int i=0;
        try {
            while (i<1000){
                // 睡个半秒再执行
                Thread.sleep(500);
                System.out.println(i++);
            }
        }catch (InterruptedException e){
            // 判断该阻塞线程是否还在
            System.out.println(Thread.currentThread().isAlive());
            // 判断该线程的中断标志位状态
            System.out.println(Thread.currentThread().isInterrupted());

            System.out.println("In Runnable");
            e.printStackTrace();
        }
    };
}
  • 結果

画像

説明:

画像

やっと

  • 読んでやりがいを感じたら、いいねをあげたいと思います。これが更新の最大のモチベーションになります。ご支援ありがとうございます。
  • Javaとコンピュータの基本的な知識に焦点を当てた私の公開アカウント[JavaFox]に注目してください。私を信じていない場合は、私を叩いてください。
  • 読んだ後に異なる意見や提案がある場合は、コメントして私たちと共有してください。皆様のご支援、ご愛顧を賜りますようお願い申し上げます。

-私は竹湖です。あなたと同じくらいプログラミングが大好きです。

画像

おすすめ

転載: blog.csdn.net/issunmingzhi/article/details/111479120