Java – Multithreading
Java est un langage de programmation multithread ce qui signifie que nous pouvons développer un programme multi-thread en utilisant Java. Un programme multi-thread contient deux parties ou plus 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 est lorsque plusieurs processus partagent des ressources de traitement communes telles qu'un processeur. Le multithreading étend l'idée du multitâche aux 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 répartit le temps de traitement non seulement entre les différentes applications, mais également entre chaque thread au sein 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 thread passe par différentes étapes de son cycle de vie. Par exemple, un thread naît, démarre, s'exécute, puis meurt. Le schéma suivant montre le cycle de vie complet d'un thread.
Voici les étapes du cycle de vie −
-
Nouveau − 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é fil né .
-
Exécutable − Après le démarrage d'un nouveau thread, le thread devient exécutable. Un thread dans cet état est considéré comme exécutant sa tâche.
-
En attente − Parfois, un thread passe à l'état d'attente pendant qu'il 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.
-
Attente chronométrée − Un thread exécutable peut entrer dans l'état d'attente temporisé 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.
-
Terminé (mort) − Un thread exécutable entre dans l'état terminé lorsqu'il termine sa tâche ou se termine autrement.
Priorités des fils
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 des threads 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 Runnable interface. Vous devrez suivre trois étapes de base −
Étape 1
Dans un premier temps, vous devez implémenter une méthode run() fournie par un Runnable interface. 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 second temps, vous allez instancier un Thread objet utilisant le constructeur suivant −
Thread(Runnable threadObj, String threadName);
Où, threadObj est une instance d'une classe qui implémente le Runnable 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 −
Démo en directclass 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 −
Sortie
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 Thread classe en suivant 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 Thread −
Démo en directclass 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 −
Sortie
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 thread
Voici la liste des méthodes importantes disponibles dans la classe Thread.
public void start()
Démarre le thread dans un chemin d'exécution séparé, puis appelle la méthode run() sur cet objet Thread.
public void run()
Si cet objet Thread a été instancié à l'aide d'une cible Runnable distincte, la méthode run() est invoquée sur cet objet Runnable.
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.
public final void setPriority(int priority)
Définit la priorité de cet objet Thread. Les valeurs possibles sont comprises entre 1 et 10.
public final void setDaemon(boolean on)
Un paramètre true désigne ce thread comme un thread démon.
jointure publique finale vide (long millisec)
Le thread actuel invoque 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 passe.
interruption publique vide()
Interrompt ce thread, l'obligeant à poursuivre son exécution s'il a été bloqué pour une raison quelconque.
booléen final public isAlive()
Renvoie true si le thread est actif, c'est-à-dire à tout moment après le démarrage du thread mais avant qu'il ne se termine.
Sr.No. | Méthode et description |
---|---|
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 |
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.
public static void yield()
Fait céder le thread en cours d'exécution à tous les autres threads de même priorité qui attendent d'être planifiés.
sommeil vide statique public (long millisec)
Provoque le blocage du thread en cours d'exécution pendant au moins le nombre de millisecondes spécifié.
public static boolean holdLock(Object x)
Renvoie vrai si le thread actuel détient le verrou sur l'objet donné.
Thread statique public currentThread()
Renvoie une référence au thread en cours d'exécution, qui est le thread qui appelle cette méthode.
vide statique public dumpStack()
Imprime la trace de la pile pour le thread en cours d'exécution, ce qui est utile lors du débogage d'une application multithread.
Sr.No. | Méthode et description |
---|---|
1 | |
2 | |
3 | |
4 | |
5 |
Exemple
Le programme ThreadClassDemo suivant illustre certaines de ces méthodes de la classe Thread. Prenons une classe DisplayMessage qui implémente 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.
Sortie
Starting hello thread... Starting goodbye thread... Hello Hello Hello Hello Hello Hello Goodbye Goodbye Goodbye Goodbye Goodbye .......
Concepts majeurs du multithreading Java
Tout en faisant de la programmation multithreading en Java, vous auriez besoin d'avoir les concepts suivants très pratiques -
-
Qu'est-ce que la synchronisation des threads ?
-
Gestion de la communication interthread
-
Gérer l'interblocage des threads
-
Opérations principales sur les threads
Java