Comprendre java.lang.Thread.State: WAITING (parking)

90

Tout d'abord, une question vraiment stupide, je me demandais simplement ce que signifie le «parking» en attente? Le thread attend-il d'être parqué ou vient-il juste d'être parqué et est donc en état d'attente? Et quand ce stationnement se produit, combien de ressources cpu / mémoire sont utilisées? Quel est le but de garer un fil?

Deuxièmement, en regardant la méthode park dans l' API de thread java

Désactive le thread actuel à des fins de planification de thread à moins que l'autorisation ne soit disponible.

Si le permis est disponible, il est consommé et l'appel revient immédiatement; sinon, le thread actuel devient désactivé à des fins de planification de thread et reste inactif jusqu'à ce que l'une des trois choses se produise .....

L'anglais n'est pas ma langue principale, j'ai donc quelques difficultés à comprendre cela, je voulais `` permettre '' comme une sorte de `` permission de garer le fil '', donc les questions qui suivent:

  • quel est le sens de cela, qu'est-ce que «permis», et qui et comment vérifie ces permis?
  • Qu'est-ce que cela signifie: «si le permis est disponible, il est consommé», est-il «stationné»?
  • suivant, si le deuxième point est vrai, alors quelle est la différence entre «parking» et «dormant»? Si j'ai un permis, je peux le garer pour toujours et sinon, je peux le rendre «dormant»?

Merci

Léonard
la source

Réponses:

36

Permettre signifie une permission de continuer l'exécution. Le stationnement signifie suspendre l'exécution jusqu'à ce qu'un permis soit disponible.

Contrairement Semaphoreaux permis de, les permis de LockSupportsont associés aux threads (c'est-à-dire que le permis est donné à un thread particulier) et ne s'accumule pas (c'est-à-dire qu'il ne peut y avoir qu'un seul permis par thread, lorsque le thread consomme le permis, il disparaît).

Vous pouvez autoriser un thread en appelant unpark(). Un thread peut suspendre son exécution jusqu'à ce que l'autorisation soit disponible (ou que le thread soit interrompu, ou que le délai ait expiré, etc.) en appelant park(). Lorsqu'une autorisation est disponible, le thread parqué le consomme et quitte une park()méthode.

axtavt
la source
2
Donc, en reprenant, si le thread A appelle «park» pour le thread B, mais que la permission est disponible, ce qui signifie «B ne peut pas être parqué», alors l'appel effectué par A revient simplement et B n'est pas parqué. Sinon, lorsqu'aucun permis n'est disponible, B doit obéir. Alors, est-ce que l'attente (parking) signifie "A essaie de me garer parce que je n'ai pas de permis mais je ne peux pas le faire pour le moment, donc je bloque A aussi"? Désolé pour cette longue phrase. Je suppose que cette attente est assez gourmande en ressources. Je me demande toujours qui gère l'ensemble des permis. Qui / quoi décide que certains threads ont un permis, tandis que d'autres non.
Leonardo
2
@Leonardo: Un thread ne peut se garer que lui-même, il n'y a aucun moyen de parquer d'autres threads. Donc, appeler park()signifie "Je veux suspendre mon exécution jusqu'à ce qu'un autre thread me donne un permis en appelant unpark()".
axtavt
Ainsi, un thread ne peut pas parquer d'autres threads, mais peut être récupéré par d'autres threads? Est-ce exact ? Alors, quand ce stationnement a-t-il lieu? Peut-être qu'un fil n'a pas de travail à faire pour le moment, et c'est une façon de le vérifier en regardant constamment son permis? Cela conviendrait bien au thread démon par exemple.
Leonardo
En outre, le WAITING (stationnement) signifie qu'il attend d'être garé ou qu'il est en état d'attente après avoir été garé? Désolé, je sais que c'est une question stupide :-)
Leonardo
3
@Leonardo: Cela signifie un état d'attente après avoir été garé.
axtavt le
11

Selon la documentation de l'état des threads java , un thread peut passer à l'état WAITING pour trois raisons:

  1. Object.wait sans délai
  2. Thread.join sans délai
  3. LockSupport.park

Lorsque vous appelez une méthode de parcage sur un thread, cela désactive le thread à des fins de planification de thread à moins que l'autorisation ne soit disponible. Vous pouvez appeler la méthode unpark pour rendre disponible le permis pour le thread donné, s'il n'était pas déjà disponible.

Ainsi, lorsque votre thread est en mode WAITING par LockSupport.park, il vous montrera WAITING (parking).

Veuillez noter que vous ne pouvez appeler le parcage que sur le fil actuel. C'est un mécanisme très utile pour implémenter un modèle de conception producteur-consommateur.

Badal
la source
3

À partir de la description de la classe (en haut du javadoc LockSupport ) où il décrit le permis:

Cette classe associe à chaque thread qui l'utilise, un permis (au sens de la classe Semaphore). Un appel au stationnement reviendra immédiatement si le permis est disponible, consommant [le permis] dans le processus; sinon [l'appel de parcage] peut bloquer. Un appel pour unpark rend le permis disponible, s'il n'était pas déjà disponible. (Contrairement aux sémaphores, les permis ne s'accumulent pas. Il y en a au plus un.)

(J'ai développé le [texte] pour le rendre plus facile à lire pour les non anglophones.)

J'espère que quelqu'un avec une compréhension plus profonde pourra élaborer là-dessus. Voir la réponse d'axtavt.

En guise de note finale, une dernière citation du javadoc:

Ces méthodes sont conçues pour être utilisées comme outils de création d'utilitaires de synchronisation de niveau supérieur et ne sont pas en elles-mêmes utiles pour la plupart des applications de contrôle d'accès concurrentiel.

Charles Goodwin
la source
3

La partie qui m'a fait revisiter cette question que je ne pouvais pas contourner en lisant la documentation, était:

Si le permis est disponible, il est consommé et l'appel revient immédiatement ...

Ainsi, lorsque le permis est «disponible», qui et comment le rend disponible, afin qu'il puisse être consommé immédiatement? C'était en quelque sorte trivial à découvrir:

public static void main(String[] args) {

    Thread parkingThread = new Thread(() -> {
        System.out.println("Will go to sleep...");
        sleepTwoSeconds();
        System.out.println("Parking...");
        // this call will return immediately since we have called  LockSupport::unpark
        // before this method is getting called, making the permit available
        LockSupport.park();
        System.out.println("After parking...");
    });

    parkingThread.start();

    // hopefully this 1 second is enough for "parkingThread" to start
    // _before_ we call un-park
    sleepOneSecond();
    System.out.println("Un-parking...");
    // making the permit available while the thread is running and has not yet
    // taken this permit, thus "LockSupport.park" will return immediately
    LockSupport.unpark(parkingThread);

}

private static void sleepTwoSeconds() {
    try {
        Thread.sleep(1000 * 2);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static void sleepOneSecond() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}    

Le code parle de lui-même, le threadest en cours d'exécution mais pas encore appelé LockSupport.park, tandis qu'un autre thread l'appelle LockSupport.unpark- rendant ainsi le permis disponible. Après cela, nous appelons LockSupport.parket cela revient immédiatement puisque le permis est disponible.

Une fois que vous y réfléchissez, c'est un peu dangereux, si vous exposez vos threads à un code que vous ne contrôlez pas et que ce code appelle LockSupport.unparkpendant que vous parkaprès cela - cela pourrait ne pas fonctionner.

Eugène
la source
Très bon point, j'aurais pensé qu'un permis donnant une activité - c'est-à-dire appeler unpark () - n'est pertinent que lorsqu'un thread est en train d'être garé.
Alfred Xiao
@AlfredXiao était d'accord, c'est quelque chose qui m'a aussi surpris, mais ça a du sens, je suppose.
Eugene le
1

Si je comprends bien, le "permis" est juste un objet qui représente si un thread peut être "non parqué" ou non. Et ceci est vérifié par le Thread lui-même (ou de JRE lorsque vous essayez de parquer un Thread). La chose "est consommé", je comprends que le permis disparaît et le Thread n'est pas désactivé.

Je pense que vous devriez en apprendre un peu plus sur le multithreading. Pensez-y comme un dispensateur d'objets appelés "permit". Vous dites à un Thread de se garer, et le Thread vérifie le distributeur, s'il y a un "permis", le Thread le prend et part (sans parc). S'il n'y a pas de "permis" dans le distributeur, le fil est garé jusqu'à ce qu'un "permis" soit disponible (et vous pouvez mettre un "permis" dans le distributeur avec unpark.

En ce qui concerne l'utilisation du processeur / de la mémoire, je pense que cela dépend du système d'exploitation, etc.

Vic
la source