Maison  >  Article  >  Un article pour comprendre comment comprendre les threads en Java

Un article pour comprendre comment comprendre les threads en Java

WBOY
WBOYavant
2022-07-18 13:45:581206parcourir

Cet article vous apporte des connaissances pertinentes sur java, qui organise principalement les problèmes liés aux threads. Un thread est un chemin d'exécution au sein d'un programme. La méthode principale que nous connaissons est en fait un chemin d'exécution distinct, s'il n'y en a qu'un. un chemin d'exécution dans le programme, alors le programme est un programme monothread. Jetons-y un coup d'œil, j'espère que cela sera utile à tout le monde.

Un article pour comprendre comment comprendre les threads en Java

Étude recommandée : "Tutoriel vidéo Java"

Le thread est un chemin d'exécution à l'intérieur d'un programme. La méthode principale que nous connaissons est en fait un chemin d'exécution distinct s'il n'y a qu'un seul chemin d'exécution dans le programme. Alors ce programme est un programme monothread ; puisqu'il y a un seul thread, il y aura également du multi-threading. Le sens littéral peut être compris comme « une technologie qui exécute plusieurs processus sur des logiciels et du matériel par rapport à un seul thread. ." Les avantages du multi-threading sont Améliorer l'utilisation du processeur. Dans un programme multithread, lorsqu'un thread doit attendre, le processeur peut exécuter d'autres threads au lieu d'attendre, améliorant ainsi considérablement l'efficacité du programme.

Création de multi-threads

Méthode 1 : hériter de la classe Thread

Processus de création de la méthode 1 :

  • Définir une sous-classe MyThread pour hériter de la classe de thread java.lang.Thread et remplacer la méthode run() ;

  • Créez un objet de la classe MyThread ;

  • Appelez la méthode start() de l'objet thread pour démarrer le thread (la méthode run() est toujours exécutée après le démarrage)

    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("子线程正在执行~~");
            }
    
        }
    }
    //输出结果(不唯一):
    //主线程正在执行~~
    //主线程正在执行~~
    //主线程正在执行~~
    //子线程正在执行~~
    //子线程正在执行~~
    //子线程正在执行~~

  • Il y en a deux) ; threads s'exécutant dans le code ci-dessus, à savoir main Le thread principal de la méthode et le thread enfant démarré en appelant start() sur l'objet thread mythread. Mais pourquoi le résultat de sortie n’est-il pas unique ? La raison en est que la préemption du processeur se produira entre les deux threads lors de l'exécution, et celui qui s'en emparera en premier s'exécutera en premier.

Alors pourquoi n'utilisons-nous pas directement l'objet thread pour appeler la méthode run() ? Si run() est appelé directement, il s'agit simplement d'une méthode d'appel normale, c'est-à-dire d'un seul thread, tandis que la méthode start() est utilisée pour démarrer les threads enfants, afin que le multithreading puisse se produire.

Avantages et inconvénients de la première méthode :

    Avantages : codage simple ;
  • Inconvénients : la classe thread a hérité de Thread et ne peut pas hériter d'autres classes, ce qui n'est pas propice à l'expansion ;
Méthode deux : implémenter l'interface Runnable ;

Processus de création de la deuxième méthode :

1. Définir une classe de tâches de thread MyRunnable pour implémenter l'interface Runnable et remplacer la méthode run() ;

2. Créer un objet MyRunnable ; Thread pour le traitement ;

4. Appeler l'objet thread La méthode start() démarre le thread

Thread constructormethodpublic Thread (String name)peut spécifier un nom pour le thread actuel ; threadpublic Thread (Runnable target)encapsule Runnable L'objet devient un objet threadpublic Thread (Runnable target, String name)Encapsule l'objet Runnable et devient un objet thread, et spécifie le thread nom
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()方法获取任务执行的结果。

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视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer