Cycle de vie d’un fil en Java

Cycle de vie d'un fil en Java

 

1. introduction

Dans cet article, nous aborderons en détail un concept de base en Java: le cycle de vie d'un thread.

Nous utiliserons un diagramme illustré rapide et, bien sûr, des extraits de code pratiques pour mieux comprendre ces états lors de l'exécution du thread.

Pour commencer à comprendre les threads en Java,this article sur la création d'un thread est un bon point de départ.

2. Multithreading en Java

In the Java language, multithreading is driven by the core concept of a Thread. Au cours de leur cycle de vie, les threads passent par différents états:

image

3. Cycle de vie d'un fil en Java

La classejava.lang.Thread contient unstatic State enum – qui définit ses états potentiels. À tout moment, le fil ne peut être que dans l'un des états suivants:

  1. NEW – nouvellement créé thread qui n'a pas encore démarré l'exécution

  2. RUNNABLE – est en cours d'exécution ou prêt à être exécuté, mais il attend l'allocation de ressources

  3. BLOCKED – en attente d'acquérir un verrouillage du moniteur pour entrer ou entrer de nouveau dans un bloc / méthode synchronisé

  4. WAITING – en attente d'un autre thread pour effectuer une action particulière sans limite de temps

  5. TIMED_WAITING – en attente d'un autre thread pour effectuer une action spécifique pendant une période spécifiée

  6. TERMINATED – a terminé son exécution

Tous ces états sont couverts dans le diagramme ci-dessus; discutons maintenant de chacun de ces éléments en détail.

3.1. New

A NEW Thread (or a Born Thread) is a thread that’s been created but not yet started. Il reste dans cet état jusqu'à ce que nous le démarrions en utilisant la méthodestart().

L'extrait de code suivant montre un thread nouvellement créé qui est dans l'étatNEW:

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
Log.info(t.getState());

Puisque nous n’avons pas démarré le thread mentionné, la méthodet.getState() imprime:

NEW

3.2. Runnable

Lorsque nous avons créé un nouveau thread et appelé la méthodestart() là-dessus, il est passé de l’étatNEW à l’étatRUNNABLE. Threads in this state are either running or ready to run, but they’re waiting for resource allocation from the system.

Dans un environnement multithread, le planificateur de threads (qui fait partie de la machine virtuelle Java) alloue une durée fixe à chaque thread. Il s'exécute donc pendant un certain temps, puis abandonne le contrôle à d'autres threadsRUNNABLE.

Par exemple, ajoutons la méthodet.start() à notre code précédent et essayons d'accéder à son état actuel:

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
t.start();
Log.info(t.getState());

Ce code estmost likely pour renvoyer la sortie comme:

RUNNABLE

Notez que dans cet exemple, il n’est pas toujours garanti que lorsque notre contrôle atteindrat.getState(), il sera toujours à l’étatRUNNABLE.

Il peut arriver qu'il ait été immédiatement planifié par lesThread-Scheduler et peut finir son exécution. Dans de tels cas, nous pouvons obtenir une sortie différente.

3.3. Bloqué

Un thread est à l'étatBLOCKED lorsqu'il n'est actuellement pas éligible pour s'exécuter. It enters this state when it is waiting for a monitor lock and is trying to access a section of code that is locked by some other thread.

Essayons de reproduire cet état:

public class BlockedState {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new DemoThreadB());
        Thread t2 = new Thread(new DemoThreadB());

        t1.start();
        t2.start();

        Thread.sleep(1000);

        Log.info(t2.getState());
        System.exit(0);
    }
}

class DemoThreadB implements Runnable {
    @Override
    public void run() {
        commonResource();
    }

    public static synchronized void commonResource() {
        while(true) {
            // Infinite loop to mimic heavy processing
            // 't1' won't leave this method
            // when 't2' try to enters this
        }
    }
}

Dans ce code:

  1. Nous avons créé deux threads différents -t1 ett2

  2. t1 démarre et entre dans la méthodecommonResource() synchronisée; cela signifie qu'un seul thread peut y accéder; tous les autres threads suivants qui tentent d'accéder à cette méthode seront bloqués de la suite de l'exécution jusqu'à ce que l'actuel termine le traitement

  3. Lorsquet1 entre dans cette méthode, elle est maintenue en boucle while infinie; c'est juste pour imiter un traitement lourd afin que tous les autres threads ne puissent pas entrer dans cette méthode

  4. Maintenant, quand nous démarronst2, il essaie d'entrer la méthodecommonResource(), qui est déjà accédée part1, donc,t2 sera conservé dans l'étatBLOCKED

Étant dans cet état, nous appelonst2.getState() et obtenons la sortie comme:

BLOCKED

3.4. Attendre

A thread is in WAITING state when it’s waiting for some other thread to perform a particular action.According to JavaDocs, n'importe quel thread peut entrer dans cet état en appelant l'une des trois méthodes suivantes:

  1. object.wait()

  2. thread.join() ou

  3. LockSupport.park()

Notez que danswait() etjoin() - nous ne définissons aucune période de temporisation car ce scénario est couvert dans la section suivante.

Nous avonsa separate tutorial qui discute en détail de l'utilisation dewait(),notify() etnotifyAll().

Pour l'instant, essayons de reproduire cet état:

public class WaitingState implements Runnable {
    public static Thread t1;

    public static void main(String[] args) {
        t1 = new Thread(new WaitingState());
        t1.start();
    }

    public void run() {
        Thread t2 = new Thread(new DemoThreadWS());
        t2.start();

        try {
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

class DemoThreadWS implements Runnable {
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }

        Log.info(WaitingState.t1.getState());
    }
}

Voyons ce que nous faisons ici:

  1. Nous avons créé et démarré lest1

  2. t1 crée unt2 et le démarre

  3. Pendant que le traitement det2 se poursuit, nous appelonst2.join(), cela mett1 à l'étatWAITING jusqu'à ce quet2 ait terminé l'exécution

  4. Puisquet1 attend la fin det2, nous appelonst1.getState() depuist2

Le résultat ici est, comme vous vous en doutez:

WAITING

3.5. Attente chronométrée

Un thread est dans l'étatTIMED_WAITING lorsqu'il attend qu'un autre thread exécute une action particulière dans un laps de temps spécifié.

According to JavaDocs, il y a cinq façons de mettre un thread sur l'étatTIMED_WAITING:

  1. thread.sleep(long millis)

  2. wait(int timeout) ouwait(int timeout, int nanos)

  3. thread.join(long millis)

  4. LockSupport.parkNanos

  5. LockSupport.parkUntil

Pour en savoir plus sur les différences entrewait() etsleep() en Java, jetez un œil àthis dedicated article here.

Pour l'instant, essayons de reproduire rapidement cet état:

public class TimedWaitingState {
    public static void main(String[] args) throws InterruptedException {
        DemoThread obj1 = new DemoThread();
        Thread t1 = new Thread(obj1);
        t1.start();

        // The following sleep will give enough time for ThreadScheduler
        // to start processing of thread t1
        Thread.sleep(1000);
        Log.info(t1.getState());
    }
}

class DemoThread implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

Ici, nous avons créé et démarré un threadt1 qui est entré en état de veille avec un délai d'expiration de 5 secondes; la sortie sera:

TIMED_WAITING

3.6. Terminé

C'est l'état d'un fil mort. It’s in the TERMINATED state when it has either finished execution or was terminated abnormally.

Nous avonsa dedicated article qui traite de différentes manières d'arrêter le thread.

Essayons d'atteindre cet état dans l'exemple suivant:

public class TerminatedState implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new TerminatedState());
        t1.start();
        // The following sleep method will give enough time for
        // thread t1 to complete
        Thread.sleep(1000);
        Log.info(t1.getState());
    }

    @Override
    public void run() {
        // No processing in this block
    }
}

Ici, alors que nous avons démarré le threadt1, la toute prochaine instructionThread.sleep(1000) donne assez de temps pour quet1 se termine et donc ce programme nous donne la sortie comme:

TERMINATED

4. Conclusion

Dans ce tutoriel, nous avons appris le cycle de vie d'un thread en Java. Nous avons examiné les six états définis par l'énumérationThread.State et les avons reproduits avec des exemples rapides.

Bien que les extraits de code donnent la même sortie sur presque toutes les machines, dans certains cas exceptionnels, nous pouvons obtenir des sorties différentes car le comportement exact de Thread Scheduler ne peut pas être déterminé.

Et, comme toujours, les extraits de code utilisés ici sontavailable on GitHub.