【Java学習まとめ】マルチスレッド

1. スレッドの紹介

1. プロセスとは:

プロセスはプログラムの実行プロセスであり、システムがリソースを割り当ててスケジュールするための独立した単位です。平たく言えば、プロセスとは、コンピューターで実行される WeChat、Eclipse、idea などのオペレーティング システムで実行されるプログラムです。

2. スレッドとは

スレッドは、オペレーティング システムが操作のスケジューリングを実行できる最小単位です。プロセスには少なくとも 1 つのスレッドがあり、プログラムには複数のスレッドが存在する場合があります。

3. マルチスレッド化

複数のスレッドを同時に実行できるプログラムはマルチスレッドです。たとえば、ビデオを視聴するとき、プログラムは同時に画像をロードし、字幕を取得し、弾幕を取得します。

2番目に、スレッドの作成

1. Threadクラスを継承する

ステップ:

(1) スレッドクラスを作成し、Threadクラスを継承する
(2) run()メソッドを書き換え、スレッドの実行本体を記述する
(3) スレッドオブジェクトを作成し、start()メソッドを呼び出してスレッドを開始する サンプル
コード以下のとおりであります:

public class TestThread extends Thread{
    
    
    @Override
    public void run() {
    
    
        //重写run方法线程执行体
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("testThread线程第"+i+"次执行");
        }
    }
    public static void main(String[] args) {
    
    
    	//创建线程对象
        TestThread testThread = new TestThread();
        //调用start()方法开启线程
        testThread.start();//子线程开启,和主线程交替执行
        //main线程执行一个for循换
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("main线程第"+i+"次执行");
        }
    }
}

実行結果は下図のようにtestThreadとメインスレッドを交互に100回実行します。出力の一部がインターセプトされます。

2. Runnableインターフェイスを実装する

ステップ:

(1) Runnable インターフェースを実装する MyRunnable クラスを定義する
(2) run() メソッドを実装し、スレッドの実行本体を記述する
(3) Runnable インターフェースの実装クラスのオブジェクトを作成する
(4) スレッド オブジェクトを作成し、start メソッドを呼び出す() メソッドでスレッドを開始します
。サンプルコードは次のとおりです。

public class TestRunnable implements Runnable{
    
    
    @Override
    public void run() {
    
    
        //重写run方法线程体
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("testRunnable线程第"+i+"次执行");
        }
    }
    public static void main(String[] args) {
    
    
        //创建Runnable接口的实现类对象
        TestRunnable testRunnable = new TestRunnable();
        //创建线程对象,通过线程对象来开启我们的线程,代理
        Thread thread = new Thread(testRunnable);
        //调用start方法,启动线程
        thread.start();//子线程开启,和主线程交替执行
		//main线程执行for循换
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("main线程第"+i+"次执行");
        }
    }
}

実行結果 testThread と main の 2 つのスレッドが交互に 100 回実行されます。これは前のプログラムと同じです。

3. Callableインターフェイスを実装する

ステップ
(1) 値の型を返す必要がある Callable インターフェイスの実装
(2) 例外をスローする必要がある呼び出しメソッドを書き直す
(3) ターゲット オブジェクトを作成する (4
) 実行サービスを作成する
(5) サブミット実行
(6) 結果の取得
(7) クローズサーブ

public class TestCallable implements Callable<Boolean> {
    
    
    //重写call方法
    @Override
    public Boolean call() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("testCallable线程执行了"+i);
        }
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        TestCallable testCallable = new TestCallable();
        //创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(1);
        //提交执行
        Future<Boolean> future = service.submit(testCallable);
        //获取结果
        Boolean result = future.get();
        //关闭服务
        service.shutdownNow();
    }
}

3. スレッドの状態

1. スレッドの 5 つの状態

(1) 新しい状態 (New): スレッド オブジェクトが作成されると、新しい状態になります。実行
(2) Ready 状態 (Runnable): スレッド オブジェクトの start() メソッドを呼び出した後、スレッドは Ready 状態になります。この時点で、スレッドは待機キューに入り、CPU による実行がいつでもスケジュールされる可能性があります。
(3) 実行状態 (Running): run メソッドが実行されると、スレッドは CPU の実行権限を取得し、実行状態になります。
(4) ブロック状態 (Blocked): ブロック状態とは、スレッドが何らかの理由で CPU の使用権を放棄し、一時的に実行を停止することを意味します。プログラムの実行中に、スリープ、待機、参加などのメソッドに遭遇したり、同期ロックの取得に失敗したりすると、ブロック状態になります。
(5) デッド状態 (Dead): スレッドは実行を終了するか、例外により run() メソッドを終了し、スレッドはライフサイクルを終了します。

2. スレッド状態図:

ここに画像の説明を挿入

3. 糸止め

  • スレッドの run() メソッドの実行が終了すると、スレッドは自然に終了します。
  • JDK には stop() メソッドと destroy() メソッドが用意されています (非推奨)。
  • ブール変数 flag をフラグ ビットとして定義することをお勧めします。flag=false の場合、スレッドは終了します。
public class TestStop implements Runnable{
    
    
	//1.设置一个标志位
    private boolean flag = true;
    @Override
    public void run() {
    
    
        while (flag){
    
    
            System.out.println("run...Thread");
        }
    }
    //2.设置一个公开的方法停止线程,转移标志位
    public void stop(){
    
    
        this.flag = false;
    }
}

4. スレッドのブロックと待機

(1) スレッドスリープ

  • Threadクラスのsleep()メソッドを呼び出すことでスレッドのスリープを実現できます。
  • sleep メソッドのオーバーロード: sleep(long millis) はスリープ時間 (ミリ秒単位) で渡すことができます。つまり、現在のスレッドをミリミリ秒間スリープさせます。sleep(long millis, int nanos) メソッドは、現在のスレッドをミリミリ + ナノ秒間スリープさせます。
  • スリープ時間に達する前に、スレッドはブロック状態 (Blocked) に入ります。
  • スリープ時間が経過すると、スレッドは準備完了状態 (実行可能) になります。
  • sleep はネットワーク遅延、カウントダウンなどをシミュレートできます。
  • スレッドがスリープ状態になると、ロックは解放されません。

(2) スレッドの丁寧さ

  • Thread クラスで yield() メソッドを呼び出すと、スレッドの丁寧さを実現できます。
  • ポライト スレッド。現在実行中のスレッドは一時停止されますが、ブロック状態 (Blocked) にはなりません。yield メソッドを実行した後も、まだ準備完了状態 (実行可能) です。
  • ポライトスレッドは実際にはこの実行の機会を放棄し、CPU を再スケジュールさせます。もちろん、CPU の次のスケジューリングは他のスレッドを実行することになる場合もあれば、このスレッドがスケジュールされる場合もあります。次回どのスレッドが実行されるようにスケジュールされるかはランダムです。

(3) スレッドの結合

  • Thread クラスの join() メソッドを呼び出して、スレッドをマージします。
  • スレッドをマージし、複数のスレッドを 1 つにマージします。join()メソッドを呼び出したスレッドを先に実行し、そのスレッドの実行後に他のスレッドを実行するというものです。
  • このスレッドが最初に実行されると、他のスレッドはブロック状態 (Blocked) になります。

5. スレッド状態の観察

Thread クラスの getState() メソッドは、スレッドの状態を監視し、スレッドの状態を取得するための戻り値を提供します。

4. スレッドの同期

1。概要

(1) 同時実行とは何ですか?
同時実行性: 同じオブジェクトが複数のスレッドによって同時に操作されます。
(2) スレッド同期が必要なのはなぜですか?
日常生活では、同時多発的な現象が頻繁に起こります。同じオブジェクトは同時に多くのスレッド操作によって変更されます。たとえば、チケット取得ソフトウェアがチケットを取得しているとき、何千人ものユーザーが同時にチケットを購入します。この時点でスレッドの同期が実行されないと、オブジェクトに対する操作が非常に混乱することになります。
この状況に対する最善の解決策は、全員が並んで 1 つずつ操作できるようにすることです。同様に、スレッド同期もスレッドに導入できます。スレッド同期は実際には待機メカニズムであり、複数のユーザーがこのオブジェクトにアクセスする必要があります。スレッドはこのオブジェクトの待機プールに入ってキューを形成し、前のスレッドが使い果たされるのを待ってから、次のスレッドがそれを使用します。

2. 同期方法と同期ブロック

  • 同期キーワードはロックです。スレッドがオブジェクトを操作すると、そのスレッドはロックを取得し、その後、他のスレッドがそのオブジェクトを操作しようとすると、ブロックされた状態 (Blocked) になります。前のスレッドがオブジェクトの操作を終了してロックを解放するまで、後続のスレッドはロックを取得してオブジェクトを操作できます。
  • 例: チケットを購入する場合、最初にチケットを購入する人が 1 人いますが、チケット購入プロセス中、他の人はチケットを操作できず、キュー状態に入る必要があります。前の人がチケットを買うのを待ってから、後ろの人がチケットを購入し始めることができます。この操作により、2 人が重複してチケットを購入することを防ぐことができます。
  • synchronized キーワードには、synchronized メソッドと synchronized ブロックという 2 つの使用法が含まれます。

(1)synchronized方法

同期メソッドは、メソッドに synchronized 修飾子を追加することで実装できます。
欠点: メソッド内で変更が必要なコンテンツのみをロックする必要があるため、この方法ではロックが多すぎてリソースが無駄になります。

    private synchronized void buy() throws InterruptedException {
    
    
       /*
       方法体
       */
    }

(2) 同期ブロック

synchronized (obj){
    
    
	/*
	方法体
	*/
}

ここで、obj はロックする必要があるオブジェクトです。どのオブジェクトを変更するには、どのオブジェクトをロックするだけです。

3. スレッドのデッドロック

(1) デッドロックの概念

例: A スレッドは test1 リソースを占有し、B スレッドは test2 リソースを占有します。この時点で、A スレッドが実行を続行するために B が占有している test2 リソースを呼び出す必要がある場合、A はブロック状態に入り、B スレッドの終わりが test2 のロックを解放するまで待ってから実行を続行する必要があります。この時点で、スレッド A が占有している test1 リソースをスレッド B も必要とする場合、スレッド A と B は同時にブロック状態になり、どちらも相手の実行が完了するまで待機する必要があります。プログラムがフリーズしてしまいます。この状況はスレッドのデッドロックになります。

(2) デッドロックを回避する方法

デッドロックが発生するために必要な 4 つの条件:

  • 相互排他: リソースは一度に 1 つのプロセスによってのみ使用できます。
  • 要求と保持の条件: リソースの要求によりプロセスがブロックされた場合、プロセスは取得したリソースを保持します。
  • 非剥奪条件: プロセスによって取得されたリソースは、使い果たされるまで強制的に剥奪されません。
  • 循環待機条件: 複数のプロセス間で、先頭から末尾までの循環待機リソース関係が形成されます。

V. まとめ

1. run() メソッドと start() メソッドの違い:

  • start() メソッドを呼び出してスレッドを開始し、run メソッドを呼び出します。これは通常のメソッド呼び出しであり、新しいスレッドは開始されません。
  • start() メソッドの呼び出しには複数の実行パスがあり、メインスレッドとサブスレッドが交互に実行されますが、 run() メソッドの呼び出しにはメインスレッドの実行パスが 1 つだけあります。

2. 収量と睡眠の違い:

  • sleep()は最初にブロッキング状態に入り、終了後にレディ状態に入るというものです。yield() は直接準備完了状態に入ります。
  • Yield() は、同じかそれ以上の優先順位を与え、実行される可能性が高くなります。

おすすめ

転載: blog.csdn.net/qq_43647936/article/details/120802262