Java - Multithreading

Java est un langage de programmation multi-thread qui signifie que nous pouvons développer un programme multi-thread en utilisant Java. Un programme multithread contient deux ou plusieurs parties qui peuvent s'exécuter simultanément et chaque partie peut gérer une tâche différente en même temps en utilisant de manière optimale les ressources disponibles, en particulier lorsque votre ordinateur dispose de plusieurs processeurs.

Par définition, le multitâche se produit lorsque plusieurs processus partagent des ressources de traitement communes telles qu'un processeur. Le multi-threading étend l'idée du multitâche dans des applications où vous pouvez subdiviser des opérations spécifiques au sein d'une seule application en threads individuels. Chacun des threads peut s'exécuter en parallèle. Le système d'exploitation divise le temps de traitement non seulement entre différentes applications, mais également entre chaque thread d'une application.

Le multi-threading vous permet d'écrire de manière à ce que plusieurs activités puissent se dérouler simultanément dans le même programme.

Cycle de vie d'un fil

Un fil passe par différentes étapes de son cycle de vie. Par exemple, un thread est né, démarré, s'exécute, puis meurt. Le diagramme suivant montre le cycle de vie complet d'un thread.

Voici les étapes du cycle de vie -

  • New- Un nouveau thread commence son cycle de vie dans le nouvel état. Il reste dans cet état jusqu'à ce que le programme démarre le thread. Il est également appelé unborn thread.

  • Runnable- Après le démarrage d'un thread nouvellement né, le thread devient exécutable. Un thread dans cet état est considéré comme exécutant sa tâche.

  • Waiting- Parfois, un thread passe à l'état d'attente pendant que le thread attend qu'un autre thread exécute une tâche. Un thread revient à l'état exécutable uniquement lorsqu'un autre thread signale au thread en attente de continuer à s'exécuter.

  • Timed Waiting- Un thread exécutable peut entrer dans l'état d'attente chronométré pendant un intervalle de temps spécifié. Un thread dans cet état revient à l'état exécutable lorsque cet intervalle de temps expire ou lorsque l'événement qu'il attend se produit.

  • Terminated (Dead) - Un thread exécutable entre dans l'état terminé lorsqu'il termine sa tâche ou s'arrête autrement.

Priorités des threads

Chaque thread Java a une priorité qui aide le système d'exploitation à déterminer l'ordre dans lequel les threads sont planifiés.

Les priorités des threads Java sont comprises entre MIN_PRIORITY (une constante de 1) et MAX_PRIORITY (une constante de 10). Par défaut, chaque thread a la priorité NORM_PRIORITY (une constante de 5).

Les threads avec une priorité plus élevée sont plus importants pour un programme et doivent se voir allouer du temps processeur avant les threads de priorité inférieure. Cependant, les priorités de thread ne peuvent pas garantir l'ordre dans lequel les threads s'exécutent et dépendent beaucoup de la plate-forme.

Créer un thread en implémentant une interface exécutable

Si votre classe est destinée à être exécutée en tant que thread, vous pouvez y parvenir en implémentant un Runnableinterface. Vous devrez suivre trois étapes de base -

Étape 1

Dans un premier temps, vous devez implémenter une méthode run () fournie par un Runnableinterface. Cette méthode fournit un point d'entrée pour le thread et vous placerez votre logique métier complète dans cette méthode. Voici une syntaxe simple de la méthode run () -

public void run( )

Étape 2

Dans un deuxième temps, vous instanciez un Thread objet utilisant le constructeur suivant -

Thread(Runnable threadObj, String threadName);

Où, threadObj est une instance d'une classe qui implémente leRunnable interface et threadName est le nom donné au nouveau fil.

Étape 3

Une fois qu'un objet Thread est créé, vous pouvez le démarrer en appelant start()méthode, qui exécute un appel à la méthode run (). Voici une syntaxe simple de la méthode start () -

void start();

Exemple

Voici un exemple qui crée un nouveau thread et commence à l'exécuter -

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

Cela produira le résultat suivant -

Production

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Créer un thread en étendant une classe de thread

La deuxième façon de créer un thread est de créer une nouvelle classe qui étend Threadclasse en utilisant les deux étapes simples suivantes. Cette approche offre plus de flexibilité dans la gestion de plusieurs threads créés à l'aide des méthodes disponibles dans la classe Thread.

Étape 1

Vous devrez remplacer run( )méthode disponible dans la classe Thread. Cette méthode fournit un point d'entrée pour le thread et vous placerez votre logique métier complète dans cette méthode. Voici une syntaxe simple de la méthode run () -

public void run( )

Étape 2

Une fois l'objet Thread créé, vous pouvez le démarrer en appelant start()méthode, qui exécute un appel à la méthode run (). Voici une syntaxe simple de la méthode start () -

void start( );

Exemple

Voici le programme précédent réécrit pour étendre le fil -

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

Cela produira le résultat suivant -

Production

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Méthodes de filetage

Voici la liste des méthodes importantes disponibles dans la classe Thread.

N ° Sr. Méthode et description
1

public void start()

Démarre le thread dans un chemin d'exécution distinct, puis appelle la méthode run () sur cet objet Thread.

2

public void run()

Si cet objet Thread a été instancié à l'aide d'une cible Runnable distincte, la méthode run () est appelée sur cet objet Runnable.

3

public final void setName(String name)

Modifie le nom de l'objet Thread. Il existe également une méthode getName () pour récupérer le nom.

4

public final void setPriority(int priority)

Définit la priorité de cet objet Thread. Les valeurs possibles sont comprises entre 1 et 10.

5

public final void setDaemon(boolean on)

Un paramètre de true désigne ce Thread comme un thread démon.

6

public final void join(long millisec)

Le thread actuel appelle cette méthode sur un deuxième thread, provoquant le blocage du thread actuel jusqu'à ce que le deuxième thread se termine ou que le nombre spécifié de millisecondes s'écoule.

sept

public void interrupt()

Interrompt ce thread, le faisant continuer son exécution s'il a été bloqué pour une raison quelconque.

8

public final boolean isAlive()

Renvoie true si le thread est actif, c'est-à-dire à tout moment après le démarrage du thread mais avant son exécution.

Les méthodes précédentes sont appelées sur un objet Thread particulier. Les méthodes suivantes de la classe Thread sont statiques. L'appel de l'une des méthodes statiques exécute l'opération sur le thread en cours d'exécution.

N ° Sr. Méthode et description
1

public static void yield()

Provoque le transfert du thread en cours d'exécution à tous les autres threads de même priorité qui attendent d'être planifiés.

2

public static void sleep(long millisec)

Provoque le blocage du thread en cours d'exécution pendant au moins le nombre de millisecondes spécifié.

3

public static boolean holdsLock(Object x)

Renvoie true si le thread actuel détient le verrou sur l'objet donné.

4

public static Thread currentThread()

Renvoie une référence au thread en cours d'exécution, qui est le thread qui appelle cette méthode.

5

public static void dumpStack()

Imprime la trace de pile pour le thread en cours d'exécution, ce qui est utile lors du débogage d'une application multithread.

Exemple

Le programme ThreadClassDemo suivant illustre certaines de ces méthodes de la classe Thread. Pensez à une classeDisplayMessage qui met en œuvre Runnable -

// File Name : DisplayMessage.java
// Create a thread to implement Runnable

public class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}

Voici une autre classe qui étend la classe Thread -

// File Name : GuessANumber.java
// Create a thread to extentd Thread

public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

Voici le programme principal, qui utilise les classes définies ci-dessus -

// File Name : ThreadClassDemo.java
public class ThreadClassDemo {

   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      } catch (InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}

Cela produira le résultat suivant. Vous pouvez essayer cet exemple encore et encore et vous obtiendrez un résultat différent à chaque fois.

Production

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

Principaux concepts de multithreading Java

Lors de la programmation multithreading en Java, vous devez avoir les concepts suivants très pratiques -