スレッドクラスと一般的に使用されるメソッド

まず、スレッドの一般的な構築方法

方法 説明する
スレッド() スレッドオブジェクトを作成する
スレッド(実行可能なターゲット) Runnableオブジェクトを使用してスレッドオブジェクトを作成する
スレッド(文字列名) スレッドオブジェクトを作成し、名前を付けます
スレッド(実行可能なターゲット、文字列名) 実行可能オブジェクトを使用してスレッドオブジェクトを作成し、それらに名前を付けます

最初の2つの方法については、前回のスレッド作成の概要で使用しました。

スレッドを作成するには、基本的に2つの方法があります。

  1. サブクラスを作成し继承自 Thread 类、Threadでrunメソッドをオーバーライドして、startメソッドを呼び出します
  2. 实现 Runnable 接口Threadのrunメソッドをオーバーライドするクラスを作成します。Threadインスタンスを作成し、自分で作成したRunnableインターフェイスを実装するクラスのインスタンスを設定して、startメソッドを呼び出します。

構築メソッド3と4は、前の2つの構築メソッドに基づいてthread objectという名前のパラメーターを追加するだけです。これは、プログラマーがデバッグするのに便利です。

コード(例として構築方法4を取り上げます):

public class func7 {
    
    
    public static void main(String[] args) {
    
    
        Thread thread = new Thread(() ->{
    
    
            while (true) {
    
    
                System.out.println("This is my Thread");
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"myThread");
        //此处用 lambda 表达式代替 Runnable 实例,更加简洁,添加了一个参数指定thread线程的名字
        thread.start();
        while (true) {
    
    
            System.out.println("my main");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

プログラマーは、JDKに付属のツールを使用して、jconsoleここで作成されたスレッドを視覚的に表示できます。

第一歩:

プログラムを実行した後、独自のjdkパス->bin->jconsole.exeを見つけます

ここに画像の説明を挿入

ステップ2:exeファイルをダブルクリックします。Javaプロセスがリストされているローカルプロセスを選択します。プログラムfunc7が表示されたら、それをクリックします。メニューバーで、スレッド列を選択します

ここに画像の説明を挿入

ステップ3:スレッド情報を表示する

ここに画像の説明を挿入

左側では、表示する必要のあるスレッドを選択できます。メインスレッドのメインと新しく作成されたスレッドmyThreadが表示されます。名前変更操作がない場合、新しく作成されたスレッドの名前はThread-0と呼ばれます。 、スレッド1、これは表示に不便です。

右側には、読み取られた時点でのスレッドの状態が表示され、スタックトレースにはコードが実行された場所が表示されます。

2.スレッドの一般的なプロパティ

属性 方法
ID getId()
名前 getName()
getState()
優先度 getPriority()
バックグラウンドスレッドかどうか isDaemon()
生きていますか 生きている()
中断されていますか isInterrupted()

説明:

  1. スレッドの一意の識別子は线程 Id

  2. 名称上記の場合に反映され、デバッグに便利です。

  3. 状态スレッドの現在の状況を示します。上記の場合、sleepメソッドが呼び出されるため、スレッドはブロック状態になります。

  4. 优先级スレッドのスケジュールの難しさを示します。スレッドが高いほど、スケジュールが簡単になります。

  5. 判断是否为后台线程バックグラウンドスレッドの場合、バックグラウンドスレッドはJavaプロセスの終了に影響しません。非バックグラウンドスレッドの場合、JVMはすべての非バックグラウンドスレッドが実行されるまで待機してから操作を終了します。プロセス全体の終わりに影響を与える

  6. 是否存活スレッドがまだ存在するかどうかを判断する方法です。Threadインスタンスオブジェクトを作成する場合、必ずしもスレッドを作成する必要はありません。実際にスレッドを作成するには、startメソッドを呼び出す必要があります。スレッドのrunメソッドが実行されると、スレッドは終了して破棄され、作成されたインスタンスオブジェクトは破棄およびリサイクルされていません。それで、创建出的实例对象和线程的生命周期是不完全相同的

    スレッドの状態では、と以外NEWの状態が生きていますTERMINATED

コード:

public class func8 {
    
    
    public static void main(String[] args) {
    
    
        Thread t = new Thread(()->{
    
    
            for (int i = 0;i < 5;i ++) {
    
    
                System.out.println("新线程~");
                try {
    
    
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        },"newThread");
        System.out.println("新线程状态:" +t.getState());
        //创建了对象,没创建线程
        t.start();
        System.out.println("新线程状态:" +t.getState());
        //创建了线程
        System.out.println("新线程Id:"+t.getId());
        System.out.println("新线程名称:"+t.getName());
        System.out.println("新线程是否为后台线程:" + t.isDaemon());
        System.out.println("新线程是否被中断:" + t.isInterrupted());
        System.out.println("新线程优先级:" + t.getPriority());
        System.out.println("主线程名称:"+Thread.currentThread().getName());
        while (t.isAlive()) {
    
    } //当t线程还存在时,主线程就搁这儿循环着,直到线程结束
        System.out.println("新线程状态:" +t.getState());//线程结束
    }
}

結果:

ここに画像の説明を挿入

3.スレッドを作成します

Threadクラスのオブジェクトを作成することは、スレッドが作成されることを意味するわけではありませんstart() 方法才是真正的在操作系统内部创建一个新的线程。実行する必要のあるタスクを記述するためにrunメソッドをオーバーライドすることにより、マルチスレッド操作が真に実現されます。

第四に、スレッドを中断します

方法1 手动设置标志位:、スレッドを中断するための条件として

public class func9 {
    
    
    private static Boolean flag = false;//手动设置的标志位 flag
    public static void main(String[] args) {
    
    
        Thread t = new Thread(() -> {
    
    
            while (!flag) {
    
    
                //flag 为真时停止循环
                System.out.println("myThread");
                try {
    
    
                    Thread.sleep(1000);//打印一次,阻塞一秒
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        });
        t.start();//创建了线程 t
        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        flag = true;
        //等3秒后,在主线程中将 flag 的值改成 true,从而使线程t循环条件不成立
    }
}

方法2:使用 Thread 实例中的标志位

public class func10 {
    
    
    public static void main(String[] args) {
    
    
        Thread t = new Thread() {
    
    
            @Override
            public void run() {
    
    
                //通过 isInerrupted()判断标志位是否为true,为true说明线程要退出
                while (!this.isInterrupted()) {
    
    
                   System.out.println("my Thread");
                   try {
    
    
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
    
    
                       e.printStackTrace();
                       //System.out.println("完善工作");
                       //break;
                   }
               }
            }
        };
        t.start();//创建新的线程
        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        t.interrupt();
        //t线程运行3秒后,通过 interrupt() 方法将标志位设置为 true
    }
}

結果:

ここに画像の説明を挿入

3秒後にフラグビットがtrueに設定され、tスレッドが中断されて終了することが期待される場合、結果はInterruptedException例外のみであることがわかります。

実際、割り込みメソッドが呼び出されると、スレッドが準備完了状態の場合、スレッド内のフラグが直接変更されます。ブロック状態の場合、InterruptedExceptionが発生します(sleepメソッドが呼び出されるため、それはブロックされており、その結果は強制的に目覚めと呼ばれます)

しかし、スレッドを中断するシグナルを受信した後、例外が発生し、単に例外を出力し、例外に応答しなかったため、スレッドを中断するシグナルが単なるリマインダーであるかのように、tスレッドはループを続けました。スレッドヒットちょうどあなたがそれを聞いていないかのように、ログが実行されます。

実際、そのようなメカニズムは理にかなっています。interruptメソッドが呼び出された場合、スレッドは中断されたと言ったときに中断されます。それは非常に不合理です。現時点では、スレッドがどこで実行されているかはわかりません。仕上げ作業を行う、それがいつ破壊されるかを決定するのはスレッド次第です

したがって、InterruptedException例外をキャッチした後に作業を完了し、ループからジャンプしてブレークを終了し、スレッドを終了する必要があります。

方法二和方法一相比更加好方法1の割り込みフラグを変更した後、その時点でスリープしていても、現在のスリープ時間が終了し、次の判定が行われ、スレッドが割り込みます。方法2睡眠中でも、割り込み信号を受信するとすぐに起動し、よりタイムリーに割り込み情報を受信します。

結果:

ここに画像の説明を挿入

ファイブ、スレッド待機

スレッドの実行順序を決定し join() 方法ます(主にスレッドの終了順序を制御します)。

public class func11 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread t1 = new Thread(() -> {
    
    
           for (int i = 0;i < 3;i ++) {
    
    
               System.out.println("my Thread~~");
               try {
    
    
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
    
    
                   e.printStackTrace();
               }
           }
        });
        t1.start();
        //t1.join();
        for (int i = 0;i < 3;i ++) {
    
    
            System.out.println("my main!!");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

結果:

ここに画像の説明を挿入

joinメソッドが呼び出されない場合、メインスレッドとt1スレッドは並行しており、結果の出力は交互になります。joinメソッドを呼び出した後、メインスレッドはブロックして待機し、joinメソッドの後のコンテンツはt1スレッドが実行されるまで実行されません。

パラメータなしのjoinメソッドの場合、終了を待機する条件はt1スレッドが終了することであり、終了しない場合は終了し続けます。このメソッドもパラメータを取得でき、待機時間はパラメータで指定できます。 。

6.スレッド参照を取得します

スレッドコードでは、さらに操作を実行するために、現在のスレッドに対応するThreadクラスのインスタンス化されたオブジェクトを取得する必要があります。

方法1:パス继承 Thread 类创建的线程、書き直されたrunメソッドで現在のスレッドのインスタンスをthis 取得

上記の中断されたスレッドの2番目のメソッドは、現在のインスタンスがthis.isInterrupted()を介して中断されているかどうかに関する情報を取得することです。

スレッドの作成方法をRunnableインスタンスを作成するメソッドに変更した場合、現在のrunメソッドはThreadクラスのメソッドではなく、これはRunnableを指し、Threadインスタンスを取得する方法はなく、その中のメソッドを使用する方法はありません

メソッド2:このメソッドを呼び出すスレッドを介しThread 类的 currentThread() 方法て、スレッドが返されるインスタンスオブジェクト

ここに画像の説明を挿入

セブン、スレッドスリープ

この方法は、多くの場合、前面に導入されます。sleep 方法

sleepメソッドが呼び出されると、スレッドはブロックして待機します。待機時間は、指定されたパラメーターによって異なります。

オペレーティングシステムはスレッド単位でスケジュールされ、各スレッドはPCBに対応し、これらのPCBは二重にリンクされたリストで編成されます。

オペレーティングシステムがPCBを就绪队列スケジュールすると、CPUで実行するPCBが選択されます。実行中のスレッドがsleepメソッドを呼び出すと、PCBは阻塞队列中央に移動し、スリープ時間が経過すると、準備完了状態に戻ります。キュー。、実行の準備ができています

joinメソッドもブロッキング待機を生成します。スレッド待機の例と同様に、メインスレッドがjoinメソッドを実行した後、メインスレッドはブロッキングキューに移動し、対応するt1スレッドの実行が終了するのを待ってから、準備完了キューに戻ります。実行する準備ができました。準備

8、スレッドステータス

スレッドの以前の一般的な属性のコードケースから、スレッドの状態は準備ができてブロックされているだけでなく、ブロックもいくつかのブロックタイプに分割されていることがわかります

//线程的状态是一个枚举类型 Thread.State
//打印 Java 线程中的所有状态
public class func13 {
    
    
    public static void main(String[] args) {
    
    
        for (Thread.State state : Thread.State.values()) {
    
    
            System.out.println(state);
        }
    }
}

結果:

ここに画像の説明を挿入

  • NEW:Threadクラスのオブジェクトが作成されたが、スレッドが作成されていない、つまりstartメソッドが呼び出されていないことを示します
  • RUNNABLE:準備完了状態
  • BLOCKED:ロックを待っている間の状態(スレッドセーフに関する次のブログを楽しみにしています)
  • WAITING:waitメソッドによってトリガーされます(次のブログを楽しみにしています)
  • TIMED_WAITING:sleepメソッドによって生成されます
  • TERMINATED:スレッドは実行されましたが、Threadクラスのオブジェクトはまだ存在しており、破棄されていません

おすすめ

転載: blog.csdn.net/weixin_46103589/article/details/124077593