Javaのスレッドを理解する方法

王林
リリース: 2023-04-29 22:01:05
転載
1182 人が閲覧しました

Javaのスレッドを理解する方法

スレッドはプログラム内の実行パスです。私たちがよく知っている主なメソッドは、実際には単一の実行パスです。プログラム内に実行パスが 1 つしかない場合、プログラムは次のようになります。単一の実行パス スレッド化されたプログラム; スレッドが 1 つであるため、マルチスレッドも存在します 文字通りの意味は、「単一のスレッドに対するソフトウェアおよびハードウェア上の複数の実行プロセスのテクノロジ」と理解できます。マルチスレッドの利点は、 CPU レートの使用率を向上させることです。マルチスレッド プログラムでは、1 つのスレッドが待機する必要がある場合、CPU は待機する代わりに他のスレッドを実行できるため、プログラムの効率が大幅に向上します。

マルチスレッドの作成

方法 1: Thread クラスを継承

方法 1 の作成プロセス:

  • サブクラスを定義するMyThread スレッド クラス java.lang.Thread を継承し、run() メソッドをオーバーライドします。

  • MyThread クラスのオブジェクトを作成します。

  • スレッド オブジェクトを呼び出す start() メソッドはスレッドを開始します (run() メソッドは起動後も実行されます);

    public class ThreadDemo01 {
        public static void main(String[] args) {
            MyThread myThread1 = new MyThread();
            myThread1.start();
            for (int i = 0; i < 3; i++) {
                System.out.println("主线程正在执行~~");
            }
        }
    }
    class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println("子线程正在执行~~");
            }
    
        }
    }
    //输出结果(不唯一):
    //主线程正在执行~~
    //主线程正在执行~~
    //主线程正在执行~~
    //子线程正在执行~~
    //子线程正在执行~~
    //子线程正在执行~~
    ログイン後にコピー

  • 上記のコードでは 2 つのスレッドが実行されています。メインスレッドとメインメソッドのスレッド 子スレッドは、オブジェクト mythread で start() を呼び出すことによって開始されました。しかし、なぜ出力結果が一意ではないのでしょうか?その理由は、実行中に 2 つのスレッド間で CPU プリエンプションが発生し、最初にそれを獲得した方が最初に実行されるためです。

それでは、スレッド オブジェクトを直接使用して run() メソッドを呼び出してみてはいかがでしょうか? run() が直接呼び出された場合、それは単なる通常の呼び出しメソッド、つまりシングルスレッドですが、start() メソッドは子スレッドの開始に使用されるため、マルチスレッドが発生する可能性があります。

方法 1 の長所と短所:

  • 長所: コーディングが簡単;

  • 短所: スレッド クラスは Thread と継承できません 他のクラスは拡張に役立ちません;

方法 2: Runnable インターフェイスの実装

方法 2 作成プロセス:

1. 定義します。スレッド タスク クラス MyRunnable Runnable インターフェイスを実装し、run() メソッドをオーバーライドします;

2. MyRunnable オブジェクトを作成します;

3. MyRunnable タスク オブジェクトを処理のために Thread に渡します;

4. スレッドを呼び出す オブジェクトの start() メソッドがスレッドを開始します;

#スレッド コンストラクターpublic Thread (文字列名)##public Thread (実行可能なターゲット) Runnable オブジェクトをカプセル化してスレッド オブジェクトにしますpublic Thread (Runnable target, String name)Runnable オブジェクトをスレッド オブジェクトとしてカプセル化し、スレッド名を指定します
public class ThreadDemo02 {
    public static void main(String[] args) {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target);
        thread.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程正在执行~~");
        }
    }
}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("子线程正在执行~~");
        }

    }
}
//输出结果(不唯一):
//主线程正在执行~~
//子线程正在执行~~
//子线程正在执行~~
//子线程正在执行~~
//主线程正在执行~~
//主线程正在执行~~
ログイン後にコピー
このコード 最初の方法との違いは、MyRunnable タスク オブジェクトを Thread にカプセル化する必要があり、他の場所は基本的に変更されていないことです。
メソッド
現在のスレッドの名前を指定できます
方法 2 の長所と短所:

長所: スレッド タスク クラスはインターフェイスのみを実装し、引き続きクラスを継承してインターフェイスを実装できるため、拡張性が高くなります。

欠点: プログラミング オブジェクトのパッケージ化にもう 1 つの層があり、スレッドに実行結果がある場合、それを直接返すことができません。

次に、Runnable インターフェイス (匿名内部クラス フォーム) を使用してマルチスレッドの作成を実現します:

1. Runnable 匿名内部クラス オブジェクトを作成します;

2. 処理は Thread に任せます;

3. スレッド オブジェクトの start() を呼び出してスレッドを開始します;

//正常版:
public class ThreadDemo01 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("子线程正在执行~~");
                }
            }
        });
        thread.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程正在执行~~");
        }
    }
}

//lambda简化版:
new Thread(()-> {
                for (int i = 0; i < 3; i++) {
                    System.out.println("子线程正在执行~~");
                }
        }).start();
ログイン後にコピー

本質的には、このメソッドには大きな違いはありません。オブジェクトは作成する必要がある単なるスレッドですが、もう 1 つは匿名の内部クラスを通じてマルチスレッドです。また、このコード ブロックはラムダ式によって効率化することもできます。この知識ポイントにまだ感銘を受けているでしょうか?忘れた場合は、次の記事を参照してください: Java でラムダ式を理解する方法 - 合理化された

方法 3: Callable インターフェイスを実装する

マルチスレッドを作成する前の 2 つの方法を学習した後、 1. 書き換えられた run() メソッドは結果を直接返すことができない; 2. スレッドの実行結果を返す必要があるビジネス シナリオには適していない。したがって、これらの問題を解決するには 3 番目の方法が必要です。

メソッド 3 の作成プロセス:

1. Callable インターフェイスを実装するクラスを定義し、call() メソッドをオーバーライドし、実行する必要があることをカプセル化します。 2. FutureTask を使用して Callable を変換します オブジェクトはスレッド タスク オブジェクトにカプセル化されます;

3. スレッド タスク オブジェクトを処理のために Thread に渡します;

4. の start() メソッドを呼び出しますスレッドを起動してタスクを実行するスレッド;

5. スレッドの実行完了後、FutureTask の get() メソッドでタスクの実行結果を取得します。

メソッド名

#説明

##public FutureTask<>(呼び出し可能呼び出し)public V get() throws Exception
public class ThreadDemo03 {
    public static void main(String[] args) throws Exception {
        MyCallable myCallable = new MyCallable();
        FutureTask<String> futureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        int sum= 0;
        for (int i = 0; i < 3; i++) {
            sum+=i;
        }
        System.out.println(sum);
        String s =futureTask.get();
        System.out.println(s);
    }
}
class MyCallable implements Callable<String > {
    @Override
    public String call(){
        int sum=0;
        for (int i = 0; i < 3; i++) {
            sum+=i;
        }
        return "子线程计算结果:"+sum;
    }
}
//输出结果:
//3
//子线程计算结果:3
ログイン後にコピー

方式三优缺点:

优点:

线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;

可以在线程执行完毕后去获取 线程执行的结果;

缺点:

编码复杂一点;

总结

Encapsulate Callable オブジェクトを FutureTask オブジェクトに変換します
呼び出しメソッドを実行するスレッドによって返された結果を取得します
方式优点缺点
继承Thread类编程比较简单,可以直接使用Thread类中的方法扩展性较差,不能再继承其他的类,不能返回线程执行的结果
实现Runnable接口扩展性强,实现该接口的同时还可以继承其他的类编程相对复杂,不能返回线程执行的结果
实现Callable接口扩展性强,实现该接口的同时还可以继承其他的类,可以得到线程的执行结果编程相对复杂

常用方法

Thread获取和设置线程名称

方法名称说明
String getName()获取当前线程的名称,默认线程名称是Thread-索引
void setName(String name)

将此线程更改为指定的名称,通过构造器也可以设置线程名称

简单地通过一段代码让大家能够清晰地了解这个代码该如何使用:

public class ThreadDemo04 {
    public static void main(String[] args) throws Exception {
        thread thread1 = new thread();
        thread1.setName("1号子线程");
        thread1.start();
        thread thread2 = new thread();
        thread2.setName("2号子线程");
        thread2.start();
    }
}
class thread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(this.getName()+"正在执行任务"+i);
        }
    }
}
//输出结果:
//2号子线程正在执行任务0
//1号子线程正在执行任务0
//2号子线程正在执行任务1
//1号子线程正在执行任务1
//2号子线程正在执行任务2
//1号子线程正在执行任务2
ログイン後にコピー

Thread类的线程休眠方法

方法名称说明
public static void sleep(long time)让当前线程休眠指定的时间后再继续执行,单位为毫秒
public class ThreadDemo05 {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
            if (i==3){
                Thread.sleep(5000);
            }
        }
    }
}
//输出结果:
//1
//2
//3
//在输出过3以后,等待5秒之后再进行输出
//4
ログイン後にコピー

以上がJavaのスレッドを理解する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート