ホームページ > よくある問題 > Java のスレッドを理解する方法を理解するための 1 つの記事

Java のスレッドを理解する方法を理解するための 1 つの記事

WBOY
リリース: 2022-07-18 13:45:58
転載
1251 人が閲覧しました

この記事では、java に関する関連知識を紹介します, 主にスレッドに関連する問題を整理します. スレッド (スレッド) はプログラム内の実行パスであり, 私たちがよく知っている主要なメソッドは実際には別の実行パス。プログラム内に実行パスが 1 つだけある場合、そのプログラムはシングルスレッド プログラムです。見てみましょう。皆さんのお役に立てれば幸いです。

Java のスレッドを理解する方法を理解するための 1 つの記事

推奨学習: 「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. Runnable インターフェイスを実装するスレッド タスク クラス MyRunnable を定義し、 run() メソッドをオーバーライドします;

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

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

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

Thread コンストラクターpublic Thread (文字列名)public Thread (Runnable target)#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中,其他的地方是基本上是没有变化的。

方式二优缺点:

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

缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。

接下来我们同样使用实现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();
ログイン後にコピー

该种方法从本质上其实并没有太大的区别只不过是一个需要创建线程对象,而另一个则是通过匿名内部类实现的多线程。并且该块代码也可以通过lambda表达式进行精简,不知道大家是否还对这个知识点有印象呢?若忘记了可以看一下这篇文章:Java中的lambda表达式如何理解——精简

方式三:实现Callable接口

在学习过前面两种创建多线程的方式以后,我们会发现存在一个问题:1、重写的run()方法不能直接返回结果;2、不适合需要返回线程执行结果的业务场景。因此,我们需要第三种方式来解决这些问题。

方式三创建过程:

1、定义类实现Callable接口,重写call()方法,封装要做的事情;

2、用FutureTask把Callable对象封装成线程任务对象;

3、把线程任务对象交给Thread处理;

4、调用Thread的start()方法启动线程,执行任务;

5、线程执行完毕后,通过FutureTask的get()方法获取任务执行的结果。

Method
現在のスレッドにすることができます。 名前を指定します。
Runnable オブジェクトをカプセル化し、スレッド オブジェクトにします。
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
ログイン後にコピー

方式三优缺点:

优点:

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

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

缺点:

编码复杂一点;

总结 

方法名称说明
public FutureTask<>(Callable call)把Callable对象封装成FutureTask对象
public V get() throws Exception 获取线程执行call方法返回的结果
方式 优点 缺点
继承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视频教程

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

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