Maison  >  Article  >  Java  >  Examinons de plus près les bonnes et les mauvaises façons de démarrer des threads en Java

Examinons de plus près les bonnes et les mauvaises façons de démarrer des threads en Java

coldplay.xixi
coldplay.xixiavant
2020-09-28 16:55:092122parcourir

Examinons de plus près les bonnes et les mauvaises façons de démarrer des threads en Java

Un examen plus approfondi des façons correctes et incorrectes de démarrer des threads en Java

Revue de l'article précédent

  1. Une analyse détaillée de les méthodes d'implémentation du multi-threading en Java sont plusieurs ? (Basé sur l'essence)

Comparaison de la méthode de démarrage et de la méthode d'exécution

Démonstration de code :

/**
 * <p>
 * start() 和 run() 的比较
 * </p>
 *
 * @author 踏雪彡寻梅
 * @version 1.0
 * @date 2020/9/20 - 16:15
 * @since JDK1.8
 */public class StartAndRunMethod {    public static void main(String[] args) {        // run 方法演示
        // 输出: name: main
        // 说明由主线程去执行的, 不符合新建一个线程的本意
        Runnable runnable = () -> {
            System.out.println("name: " + Thread.currentThread().getName());
        };
        runnable.run();        // start 方法演示
        // 输出: name: Thread-0
        // 说明新建了一个线程, 符合本意
        new Thread(runnable).start();
    }
}复制代码

À partir de l'exemple ci-dessus Les deux points suivants peuvent être analysés :

  • L'utilisation directe de la méthode run ne démarrera pas un nouveau fil de discussion. (Mauvais chemin) La méthode

  • start démarre un nouveau fil de discussion. (Manière correcte)

démarrer l'analyse de la méthode

démarrer la signification et les précautions de la méthode

  • start la méthode peut être démarrée A nouveau fil.

    • Une fois que l'objet thread a appelé la méthode start après l'initialisation, le thread actuel (généralement le thread principal) demandera à la machine virtuelle JVM de démarrer ce nouveau thread ici s'il est libre.
    • En d'autres termes, l'essence du démarrage d'un nouveau thread est de demander à la JVM d'exécuter ce thread.
    • Quant au moment où ce fil peut s'exécuter, ce n'est pas simplement décidé par nous, mais par le planificateur de fil.
    • S'il est très chargé, même si nous exécutons la méthode start, nous ne pourrons peut-être pas démarrer le fil immédiatement.
    • Ainsi, après l'appel de la méthode srtart, cela ne signifie pas que cette méthode a commencé à s'exécuter. Il se peut qu'il ne fonctionne que plus tard, ou qu'il ne fonctionne pas pendant une longue période, par exemple en cas de famine.
    • Cela prouve également que dans certains cas, le thread 1 appelle d'abord la méthode start, puis le thread 2 appelle la méthode start, pour constater que le thread 2 exécute d'abord le thread 1, puis s'exécute.
    • Résumé : L'ordre dans lequel les méthodes start sont appelées ne détermine pas l'ordre d'exécution réel du thread.
    • Notes
      • start La méthode impliquera deux threads.
      • Le premier est le thread principal, car il faut avoir un thread principal ou d'autres threads (même si ce n'est pas le thread principal) pour exécuter cette start méthode, et le second est le nouveau thread .
      • Dans de nombreux cas, le thread principal qui crée le thread pour nous est ignoré. Ne pensez pas à tort que l'appel de start est déjà exécuté par le thread enfant. Cette instruction est en fait exécutée par le thread principal ou. le thread parent Exécuté, un nouveau thread sera créé après avoir été exécuté.
  • start Préparation à la méthode pour créer un nouveau fil

    • Tout d'abord, il va se mettre dans le état prêt.
      • L'état prêt signifie que d'autres ressources que le CPU ont été obtenues, telles que le contexte, la pile, l'état du thread et le PC (le PC est un registre, le PC pointe vers l'emplacement où le programme s'exécute), etc. . ont été fixés.
    • Après avoir terminé ces préparatifs, tout est prêt et tout ce dont vous avez besoin est Dongfeng, qui est la ressource CPU.
    • Après avoir terminé le travail de préparation, le thread peut être programmé par la JVM ou le système d'exploitation à l'état d'exécution pour attendre d'obtenir les ressources CPU, puis il entrera réellement dans l'état d'exécution pour exécuter le code dans le run méthode.
  • Remarque : La méthode de démarrage ne peut pas être exécutée à plusieurs reprises

    • Exemple de code

      /**
      * <p>
      * 演示不能重复的执行 start 方法(两次及以上), 否则会报错
      * </p>
      *
      * @author 踏雪彡寻梅
      * @version 1.0
      * @date 2020/9/20 - 16:47
      * @since JDK1.8
      */public class CantStartTwice {    public static void main(String[] args) {
              Runnable runnable = () -> {
                  System.out.println("name: " + Thread.currentThread().getName());
              };
              Thread thread = new Thread(runnable);        // 输出: name: Thread-0
              thread.start();        // 输出: 抛出 java.lang.IllegalThreadStateException
              // 即非法线程状态异常(线程状态不符合规定)
              thread.start();
          }
      }复制代码
    • La raison de l'erreur

      • start Une fois l'exécution démarrée, l'état du thread entrera dans l'état suivant à partir de l'état initial New, tel que Runnable, puis une fois le le thread termine l'exécution, le thread deviendra un état terminé et l'état terminé ne pourra jamais être renvoyé, donc l'exception ci-dessus sera levée, ce qui signifie qu'il ne peut pas revenir à l'état initial. La description ici n'est pas assez claire, regardons le code source pour mieux comprendre.

Démarrer l'analyse du code source de la méthode

Code source

public synchronized void start() {    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
    // 第一步, 检查线程状态是否为初始状态, 这里也就是上面抛出异常的原因
    if (threadStatus != 0)        throw new IllegalThreadStateException();    /* Notify the group that this thread is about to be started
     * so that it can be added to the group&#39;s list of threads
     * and the group&#39;s unstarted count can be decremented. */
    // 第二步, 加入线程组
    group.add(this);    boolean started = false;    try {        // 第三步, 调用 start0 方法
        start0();
        started = true;
    } finally {        try {            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}复制代码

Processus dans le code source

Étape 1 : Lors du démarrage d'un nouveau thread, il vérifiera d'abord si l'état du thread est l'état initial, ce qui est également la raison pour laquelle l'exception ci-dessus est levée. C'est-à-dire le code suivant :

if (threadStatus != 0)    throw new IllegalThreadStateException();复制代码

L'annotation de cette variable threadStatus est la suivante, ce qui signifie que l'état du thread Java est initialement exprimé par 0 (pas encore démarré) :

/* Java thread status for tools,
 * initialized to indicate thread &#39;not yet started&#39;
 */private volatile int threadStatus = 0;复制代码

Étape 2 :Ajoutez-le au groupe de discussions. C'est à dire le code suivant :

group.add(this);复制代码

La troisième étape : Enfin appeler la start0() méthode native (native signifie que son code n'est pas implémenté par Java, mais par C/C++, L'implémentation spécifique peut être vue dans le JDK, il suffit de le comprendre), c'est-à-dire le code suivant :

boolean started = false;try {    // 第三步, 调用 start0 方法
    start0();
    started = true;
} finally {    try {        if (!started) {
            group.threadStartFailed(this);
        }
    } catch (Throwable ignore) {        /* do nothing. If start0 threw a Throwable then
          it will be passed up the call stack */
    }
}复制代码

exécuter l'analyse de la méthode

exécuter l'analyse du code source de la méthode

@Overridepublic void run() {    // 传入了 target 对象(即 Runnable 接口的实现), 执行传入的 target 对象的 run 方法
    if (target != null) {
        target.run();
    }
}复制代码

Pour les deux méthodes d'exécution Situations

  • La première : la méthode Thread de la classe run est remplacée, la méthode Thread de run sera invalide, et la méthode run

  • Deuxième type : transmettre l'objet target (c'est-à-dire l'implémentation de l'interface Runnable), exécuter la méthode Thread originale de run puis exécuter le target Méthode run de l'objet.

  • Résumé : La méthode

    • run est une méthode ordinaire Exécuter directement la méthode run ci-dessus équivaut à exécuter ce que nous écrivons nous-mêmes. Identique à la méthode ordinaire, son thread d'exécution est donc notre thread principal.
    • Donc, si vous souhaitez réellement démarrer un fil de discussion, vous ne pouvez pas appeler directement la méthode run, mais vous devez appeler la méthode start, qui peut appeler indirectement la méthode run.

Recommandations d'apprentissage associées : bases de 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