Thread Java pour comprendre vaguement

Vous devez gérer les threads pour effectuer un traitement asynchrone et parallèle en Java. Cet article a été écrit dans l'espoir que les utilisateurs débutants à intermédiaires de Java pourront se faire une idée approximative des threads.

Qu'est-ce qu'un fil?

Les threads sont comme le chemin que vous empruntez lorsque vous exécutez un programme. Par exemple

  public static void main(String[] args) {
    run();
  }

  static void run() {
    int result = sum(1, 2);
    System.out.println(result);
  }

  static int sum(int a, int b) {
    return a + b;
  }

Lorsque vous exécutez le programme main () est appelée, run () est appelée, sum () est appelée, System.out.println () est appelée, et ainsi de suite, tout en exécutant les processus un par un. Aller. Un thread est celui qui exécute le traitement en suivant ce chemin droit.

Tout le traitement s'exécute sur des threads

Par exemple, si vous exécutez le processus à partir de la fonction principale ...

  public static void main(String[] args) {
    Thread currentThread = Thread.currentThread(); //Obtenez votre propre fil
    System.out.printf("ID:%d, Name:%s, Priority:%d, State:%s%n",
        currentThread.getId(),
        currentThread.getName(),
        currentThread.getPriority(),
        currentThread.getState());
  }

Résultat d'exécution

ID:1, Name:main, Priority:5, State:RUNNABLE

Vous pouvez voir qu'il a été exécuté dans un thread nommé main

Essayez d'écrire du code pour faire quelque chose dans un thread séparé

Branchez un autre thread à partir du thread principal et essayez d'exécuter quelque chose de manière asynchrone. Nouveau la classe Thread et appelez start ().

public class Sample {

  public static void main(String[] args) throws Exception {
    Thread thread = new Thread(() -> { //Créer un fil. Transmettez le processus que vous souhaitez exécuter au constructeur
      for (int i = 1; i < 5; i++) {
        System.out.println("thread: " + i);
        try {
          Thread.sleep(100L);
        } catch (InterruptedException e) {
          return;
        }
      }
    });

    System.out.println("main: 1");

    thread.start(); //Commencer le traitement du fil

    System.out.println("main: 2");
    Thread.sleep(150L);
    System.out.println("main: 3");

    thread.join(); //Attendez la fin du fil (si vous n'attendez pas, il n'y a pas de problème si vous ne le faites pas)
    System.out.println("main: 4");
  }
}

Résultat de sortie

main: 1
main: 2
thread: 1
thread: 2
main: 3
thread: 3
thread: 4
main: 4

Vous pouvez voir que le traitement du thread principal et le traitement du thread généré fonctionnent indépendamment.

Quelles informations contient le fil

Java gère les threads via la classe Thread. En regardant les propriétés de la classe Thread dans Intellij, cela ressemble à ceci

Screen Shot 2018-12-17 at 11.40.57.png

Je n'expliquerai que ceux que vous voyez souvent.

ID :long

Une valeur longue qui est automatiquement affectée lors de la création d'un thread. Unique et immuable.

name :String

Le nom du fil. Tout nom peut être défini avec setName (String). Si vous créez un thread avec new Thread (), des noms comme Thread-1 et Thread-2 seront définis arbitrairement.

state :Thread.State

État du fil. «Courir» ou «attendre». Le thread a un état et est dans l'un des états suivants: «NEW», «RUNNABLE», «BLOCKED», «WAITING», «TIMED_WAITING», «TERMINATED».

Voir Javadoc pour plus de détails.

interrupted :boolean

Si le fil a été interrompu.

--Cette valeur peut être définie sur true avec Thread # interruption ()

priority :int

Priorité du fil. Lorsqu'un conflit de ressources se produit, le thread avec la priorité la plus élevée est exécuté avec la priorité. La valeur par défaut est 5 (Thread.NORM_PRIORITY), la plus basse est 1 ( Thread.MIN_PRIORITY) et la plus élevée est 10 (Thread.MAX_PRIORITY). Peut être changé avec setPriority (int).

daemon: boolean

Est-ce un thread démon? Si daemon est true, il est appelé un thread démon, et s'il est false, il est appelé un thread utilisateur. La valeur par défaut est false, qui peut être définie avec setDaemon (boolean).

Programmation de divers threads

Il existe de nombreuses façons d'écrire un programme qui exécute quelque chose dans un thread séparé.

Comment utiliser Raw Thread

Le thread est démarré en mettant le processus à exécuter dans l'argument constructeur de Thread avec lambda ou new et en appelant start ().

Thread thread = new Thread(() -> {
    //Quelque chose de traitement...
});
thread.start(); //Démarrez un fil. "Quelque chose" est exécuté de manière asynchrone

Vous pouvez hériter de «Thread» et remplacer «run». (Cependant, je recommande personnellement la méthode ↑, car le traitement dépend de la classe Thread.)

class MyThread extends Thread {
  @Override
  public void run() {
    //Quelque chose de traitement...
  }
}

MyThread thread = new MyThread();
thread.start(); //Démarrez un fil. "Quelque chose" est exécuté de manière asynchrone

Comment utiliser Executor

Vous pouvez facilement créer quelque chose comme un pool de threads.

ExecutorService threadPool = Executors.newFixedThreadPool(3); //Le nombre de fils=Créer 3 pools de threads

//Essayez de mettre en traitement 100
for (int i = 0; i < 100; i++) {
  threadPool.submit(() -> { //threadPool utilise pleinement 3 threads pour exécuter le traitement d'entrée de manière régulière
    //Quelque chose de traitement...
  });
}

//Attendez la fin de tous les traitements soumis
threadPool.awaitTermination(1, TimeUnit.MINUTES);

//Arrêter le pool de threads
threadPool.shutdown();

Il y a beaucoup d'autres choses en plus de ʻExecutors.newFixedThreadPool () `.

Comment utiliser Completable Future

C'est comme Future / Promise en JavaScript. Executor interne est utilisé pour le contrôle des threads

//Exécuter le traitement de manière asynchrone
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
  //Quelque chose de traitement...
});

//Vous pouvez enregistrer un rappel dans la valeur de retour CompletableFuture
future.whenComplete((aVoid, throwable) -> { //Dans la promesse JavaScript.then()
  //Ceci est appelé lorsque "quelque chose est fait"
  // -Si "quelque chose" est terminé normalement, l'argument jetable est nul.
  // -Si une exception se produit dans "quelque chose", l'exception est passée à l'argument jetable.
});

Rupture de fil

Émettre une commande de suspension

Utilisez Thread # interruption () si vous voulez interrompre le traitement d'un thread en cours d'exécution

Thread thread = createNanikanoThread();
thread.start(); //Exécutez le fil
...
thread.interrupt(); //Envoyer une commande de suspension à un thread en cours d'exécution

Cependant, ce n'est pas parce que ʻinterrupt () `que le thread cible s'arrêtera immédiatement! Ce qui se passe lorsque vous appelez cette méthode est Une image dans laquelle «true» n'est défini que dans le champ booléen «interrompu» du thread cible (← explication un peu approximative). Fondamentalement, vous devez vérifier cet indicateur «interrompu» dans le processus du côté interrompu.

Confirmation du statut de suspension

Le traitement qui peut être interrompu doit être mis en œuvre dans cet esprit. Vous pouvez vérifier si elle a été interrompue (si l'indicateur ʻinterruptedest activé) avecThread.interrupted ()`.

//Le processus de faire quelque chose pour toujours
while (true) {
  if (Thread.interrupted()) { //Vérifiez s'il a été interrompu (* Lorsque cette méthode est appelée, le drapeau interrompu revient à false)
    throw new InterruptedException(); //Lancez une exception et quittez le processus. En gros, c'est OK si vous utilisez InterruptedException
  }
  //Traiter quelque chose
  ...
}

L'appel de Thread.interrupted () pour vérifier l'état réinitialise l'indicateur d'interruption à false. (Au fait, si vous vérifiez avec Thread.currentThread (). IsInterrupted (), il ne sera pas réinitialisé)

Certaines méthodes vérifieront le statut «interrompu». Par exemple, Thread.sleep () arrêtera de dormir et lancera une ʻInterruptedException si le drapeau ʻinterrupted est défini pendant le sommeil. (À propos, l'indicateur d'interruption est également réinitialisé à faux à ce moment)

//Le processus de faire quelque chose pour toujours
while (true) {
  Thread.sleep(1000L); //Suspend le traitement pendant 1 seconde. InterruptedException est levée si elle est interrompue pendant l'hibernation
  ...
}

Traitement des exceptions interrompues

Le fait qu'une InterruptedException ait été levée signifie que le thread a été interrompu. Un traitement approprié doit être effectué sans perdre ces informations.

Mauvais exemple 1: ignorer l'instruction d'interruption et poursuivre le traitement

J'ignore les informations selon lesquelles le fil a été interrompu et continue

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
}

Mauvais exemple 2: Envelopper et lancer avec une autre exception

Celui que tu vois souvent

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  throw new RuntimeException(ex);
}

Les informations indiquant que le thread a été interrompu ont été perdues. Lorsque vous interceptez cette exception dans le processus externe, elle sera traitée comme une erreur inattendue.

Exemple pas mal: réactivez le drapeau interrompu, puis enroulez et lancez avec une autre exception

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  Thread.currentThread().interrupt(); // Here!
  throw new RuntimeException(ex);
}

Le jugement du drapeau interrompu est laissé au traitement extérieur. L'information selon laquelle il a été interrompu survit. Bien sûr, le processus de capture de ceci à l'extérieur doit faire quelque chose pour déterminer s'il a été interrompu.

Pratique conçue personnellement: créer une exception non vérifiée dédiée

(Je ne sais pas si cette méthode est bonne. S'il vous plaît laissez-moi savoir s'il existe une meilleure façon ...)

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  throw new InterruptedRuntimeException(ex);
}

Veillez à intercepter cette InterruptedRuntimeException dans le traitement externe et à effectuer le traitement approprié.

Comme il est difficile d'essayer d'attraper à chaque fois en dormant, je crée une classe utilitaire

public class ThreadUtils {

  /**
   * @param n Temps de veille (millisecondes)
   * @throws InterruptedRuntimeException Si le thread est interrompu
   */
  public static void sleep(long n) {
    try {
      Thread.sleep(n);
    } catch (InterruptedException ex) {
      throw new InterruptedRuntimeException(ex);
    }
  }

  /**
   *Vérifiez si le thread en cours a été interrompu.
   * @throws InterruptedRuntimeException Si le thread est interrompu
   */
  public static void checkForInterruption() {
    if (Thread.interrupted()) {
      throw new InterruptedRuntimeException(ex);
    }
  }
}

À propos du traçage de pile

WIP

Recommended Posts

Thread Java pour comprendre vaguement
[java8] Pour comprendre l'API Stream
Référence Java à comprendre dans la figure
Traitement des threads Java
[Java] Map # merge est difficile à comprendre.
[Java] Introduction à Java
Comprendre le constructeur java
Deux façons de démarrer un thread en Java + @
Changements de Java 8 à Java 11
Somme de Java_1 à 100
[Java] Thread et exécutable
Comprendre les expressions lambda Java 8
Améliorations de Kotlin à Java
Résumé des threads sûrs ~ Java ~
Introduction à la commande java
Thread de programmation Java exécutable
Traitement des listes à comprendre avec des images - java8 stream / javaslang-
Classes et instances Java comprises dans la figure
Un ingénieur qui ne comprend pas Java est allé à JJUG CCC.
[Java] Nouvelle méthode de génération de threads (2)
Comment abaisser la version java
Migration de Cobol vers JAVA
[Java] Comment utiliser Map
Java ajoute un tableau au PDF
Comment désinstaller Java 8 (Mac)
Java pour jouer avec Function
Java - Comment créer JTable
Comment utiliser java Facultatif
Nouvelles fonctionnalités de Java7 à Java8
Comment réduire les images Java
Comment rédiger un commentaire java
Comment utiliser la classe Java
Connectez-vous de Java à PostgreSQL
[Java] Comment utiliser removeAll ()
[Java] Comment afficher les Wingdings
[Java] Introduction à l'expression lambda
Comment utiliser Java Map
Comment définir des constantes Java
Connectez-vous à DB avec Java
Connectez-vous à MySQL 8 avec Java
[java] Raisons d'utiliser statique
Java thread sans danger pour vous
Traitement des listes à comprendre avec des images --java8 stream / javaslang --bonus
Comment utiliser les variables Java
[Java] Introduction à l'API Stream
Java8 pour démarrer maintenant ~ Facultatif ~
Comment convertir la base Java
Je ne suis pas sûr du traitement parallèle Java
[Java] Comment implémenter le multithreading
De Java inefficace à Java efficace
Comment initialiser un tableau Java
[Java] Nouvelle méthode de génération de threads (1)
[Introduction aux jeux Janken (comme)] Java
Entrée dans la console Java
Comprendre comment la programmation fonctionnelle a été introduite dans Java d'un seul coup