Quelles sont les principales utilisations de yield() et en quoi diffère-t-il de join () et interrupt ()?


Je suis un peu confus au sujet de l'utilisation de yield() méthode en Java, en particulier dans l'exemple de code ci-dessous. J'ai également lu que yield () est 'utilisé pour empêcher l'exécution d'un thread'.

, Mes questions sont:

  1. Je crois que le code ci-dessous donne la même sortie à la fois lorsque vous utilisez yield() et lorsque vous ne l'utilisez pas. Est-ce correct?

  2. Ce sont, en fait, les principales utilisations de yield()?

  3. En quoi yield() est-il différent de join() et interrupt() méthodes?

L'exemple de code:

public class MyRunnable implements Runnable {

   public static void main(String[] args) {
      Thread t = new Thread(new MyRunnable());
      t.start();

      for(int i=0; i<5; i++) {
          System.out.println("Inside main");
      }
   }

   public void run() {
      for(int i=0; i<5; i++) {
          System.out.println("Inside run");
          Thread.yield();
      }
   }
}

J'obtiens la même sortie en utilisant le code ci-dessus avec et sans utiliser yield():

Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run
Author: BradleyDotNET, 2011-08-08

9 answers

Source: http://www.javamex.com/tutorials/threads/yield.shtml

Fenêtres

Dans l'implémentation Hotspot, la façon dont Thread.yield() fonctionne a changé entre Java 5 et Java 6.

Dans Java 5, Thread.yield() appelle l'appel d'API Windows Sleep(0). Ce a pour effet spécial de effacer le quantum du thread actuel et le mettre à la fin de la file d'attente pour son niveau de priorité . Dans d'autres les mots, tous les threads exécutables de même priorité (et ceux de plus grande priorité) aura une chance de s'exécuter avant que le thread donné ne soit le suivant compte tenu du temps de calcul. Quand il sera finalement reprogrammé, il reviendra avec un full full quantum, mais ne "reporte" aucun des reste quantique à partir du moment de céder. Ce comportement est un peu différent d'un sommeil non nul où le fil de sommeil perd généralement 1 valeur quantique (en effet, 1/3 d'une tique de 10 ou 15 ms).

Dans Java 6, ce comportement a été modifié. La machine virtuelle Hotspot implémente maintenant Thread.yield() en utilisant l'appel d'API Windows SwitchToThread(). Cet appel fait en sorte que le thread actuel abandonne son intervalle de temps actuel , mais pas son toute quantique. Cela signifie que selon les priorités des autres threads, le thread donnant peut être planifié en une seule interruption période plus tard. (Voir la section sur thread scheduling pour plus d'informations informations sur timeslices.)

Linux

Sous Linux, Hotspot appelle simplement sched_yield(). Les conséquences de cet appel sont un peu différents, et peut-être plus grave que sous Fenêtres:

  • un thread donné n'obtiendra pas une autre tranche de CPU jusqu'à ce que tous les autres threads aient eu une tranche de CPU;
  • (au moins dans le noyau 2.6.8 à partir de), le fait que le thread a cédé est implicitement pris en compte par les heuristiques du planificateur sur son CPU récent allocation-donc, implicitement, un thread qui a yielded pourrait recevoir plus de CPU lorsqu'il est prévu à l'avenir.

(Voir la section sur thread scheduling pour plus de détails sur les priorités et des algorithmes de planification.)

Quand utiliser yield()?

Je dirais pratiquement jamais. Son comportement n'est pas défini de manière standard et il existe généralement de meilleures façons d'effectuer les tâches que vous peut-être vouloir effectuer avec yield ():

  • si vous essayez de n'utiliser qu'une partie du CPU , vous pouvez le faire de manière plus contrôlable en estimant la quantité de CPU du thread a utilisé dans son dernier bloc de traitement, puis couchage pour certains durée de compensation: voir la méthode sleep () ;
  • si vous êtes en attente d'un processus ou d'une ressource pour terminer ou devenir disponible, il existe des moyens plus efficaces pour y parvenir, comme en utilisant join () pour attendez qu'un autre thread se termine, en utilisant le mécanisme wait / notify pour permettre à un thread de signaler à un autre qu'une tâche est terminée, ou idéalement en utilisant l'un des Java 5 la simultanéité de constructions comme un Sémaphore ou file d'attente de blocage.
 87
Author: Sathwick, 2016-11-02 10:58:54

Je vois que la question a été réactivée avec une prime, demandant maintenant quelles sont les utilisations pratiques de yield. Je vais donner un exemple de mon expérience.

Comme nous le savons, yield force le thread appelant à abandonner le processeur sur lequel il s'exécute afin qu'un autre thread puisse être planifié pour s'exécuter. Ceci est utile lorsque le thread actuel a terminé son travail pour l'instant mais souhaite revenir rapidement à l'avant de la file d'attente et vérifier si certaines conditions ont changé. En quoi est ce différent à partir d'une variable de condition? yield permet au thread de revenir beaucoup plus rapidement à un état en cours d'exécution. Lors de l'attente sur une variable de condition le thread est suspendu et doit attendre un autre thread pour signaler qu'il doit continuer. yield dit fondamentalement "permettre à un thread différent de s'exécuter, mais permettez-moi de me remettre au travail très rapidement car je m'attends à ce que quelque chose change dans mon état très très rapidement". Cela laisse entrevoir une rotation occupée, où une condition peut changer rapidement, mais suspendre le fil le ferait encourir un grand coup de performance.

Mais assez de babillage, voici un exemple concret: le modèle parallèle du front d'onde. Une instance de base de ce problème consiste à calculer les "îles" individuelles de 1s dans un tableau bidimensionnel rempli de 0s et de 1s. Une" île " est un groupe de cellules adjacentes l'une à l'autre verticalement ou horizontalement:

1 0 0 0
1 1 0 0
0 0 0 1
0 0 1 1
0 0 1 1

Ici, nous avons deux îles de 1: en haut à gauche et en bas à droite.

Une solution simple consiste à faire un premier passage sur l'ensemble tableau et remplacer les valeurs 1 par un compteur d'incrémentation tel qu'à la fin chaque 1 a été remplacé par son numéro de séquence dans l'ordre majeur de la ligne:

1 0 0 0
2 3 0 0
0 0 0 4
0 0 5 6
0 0 7 8

À l'étape suivante, chaque valeur est remplacée par le minimum entre elle-même et les valeurs de ses voisins:

1 0 0 0
1 1 0 0
0 0 0 4
0 0 4 4
0 0 4 4

Nous pouvons maintenant facilement déterminer que nous avons deux îles.

La partie que nous voulons exécuter en parallèle est l'étape où l'on calcule le minimum. Sans entrer dans trop de détails, chaque thread obtient des lignes dans un de manière entrelacée et repose sur les valeurs calculées par le thread traitant la ligne ci-dessus. Ainsi, chaque thread doit être légèrement en retard sur le thread traitant la ligne précédente, mais doit également suivre dans un délai raisonnable. Plus de détails et une mise en œuvre sont présentés par moi-même dans ce document. Notez l'utilisation de sleep(0) qui est plus ou moins l'équivalent C de yield.

Dans ce cas, yield a été utilisé afin de forcer chaque thread à son tour à mettre en pause, mais puisque le thread le traitement de la ligne adjacente avancerait très rapidement entre-temps, une variable de condition s'avérerait un choix désastreux.

Comme vous pouvez le voir, yield est une optimisation à grain fin. L'utiliser au mauvais endroit, par exemple en attendant une condition qui change lentement, entraînera une utilisation excessive du PROCESSEUR.

Désolé pour le long babillage, j'espère que je me suis fait comprendre.

 31
Author: Tudor, 2016-01-07 08:35:12

Sur les différences entre les yield(), interrupt() et join() - en général, pas seulement en Java:

  1. yielding : Littéralement, "céder" signifie lâcher prise, abandonner, se rendre. Un thread donnant indique au système d'exploitation (ou à la machine virtuelle, ou non) qu'il est prêt à laisser d'autres threads être planifiés à sa place. Cela indique qu'il ne fait pas quelque chose de trop critique. Ce n'est qu'un indice, cependant, et pas garanti d'avoir un effet.
  2. rejoindre : Quand plusieurs threads "joignent" sur un handle, un jeton ou une entité, tous attendent que tous les autres threads pertinents aient terminé l'exécution (entièrement ou jusqu'à leur propre jointure correspondante). Cela signifie qu'un tas de threads ont tous terminé leurs tâches. Ensuite, chacun de ces threads peut être planifié pour continuer d'autres travaux, étant en mesure de supposer que toutes ces tâches sont effectivement terminées. (À ne pas confondre avec SQL Joins!)
  3. interruption : Utilisé par un thread pour "piquer" un autre thread qui est en train de dormir, d'attendre ou de rejoindre - de sorte qu'il est prévu de continuer à fonctionner, peut-être avec une indication qu'il a été interrompu. (À ne pas confondre avec les interruptions matérielles!)

Pour Java spécifiquement, voir

  1. Rejoindre:

    Comment utiliser Thread.rejoindre? (ici sur StackOverflow)

    Quand rejoindre les threads?

  2. Rendement:

  3. Interruption:

    Est Fil.interrupt() mal? (ici sur StackOverflow)

 13
Author: einpoklum, 2017-05-23 11:55:10

Tout d'Abord, la description réelle est

Provoque une pause temporaire de l'objet thread en cours d'exécution et autoriser d'autres threads à s'exécuter.

Maintenant, il est très probable que votre thread principal exécutera la boucle cinq fois avant l'exécution de la méthode run du nouveau thread, donc tous les appels à yield ne se produiront qu'après l'exécution de la boucle dans le thread principal.

join arrêtera le thread actuel jusqu'à ce que le thread soit appelé avec join() est effectuée en cours d'exécution.

interrupt interrompra le thread sur lequel il est appelé, provoquant InterruptedException.

yield permet un changement de contexte vers d'autres threads, de sorte que ce thread ne consommera pas toute l'utilisation du PROCESSEUR du processus.

 9
Author: MByD, 2012-04-13 00:51:04

Quels sont, en fait, les principales utilisations de rendement()?

Yield suggère à la CPU que vous pouvez arrêter le thread actuel et commencer à exécuter des threads avec une priorité plus élevée. En d'autres termes, assigner une valeur de priorité faible au thread actuel pour laisser de la place à des threads plus critiques.

Je crois que le code ci-dessous donne la même sortie à la fois lorsque vous utilisez yield() et lorsque vous ne l'utilisez pas. Est-ce correct?

NON, les deux produiront des résultats différents. Sans yield (), une fois que le thread aura le contrôle, il exécutera la boucle 'Inside run' en une seule fois. Cependant, avec un yield (), une fois que le thread aura le contrôle, il imprimera le 'Inside run' une fois, puis transmettra le contrôle à un autre thread, le cas échéant. Si aucun thread n'est en attente, ce thread sera repris. Ainsi, chaque fois que "Inside run" est exécuté, il recherchera d'autres threads à exécuter et si aucun thread n'est disponible, le thread actuel continuera à s'exécuter.

De quelle manière est yield() différent des méthodes join() et interrupt ()?

Yield() est pour donner de la place à d'autres threads importants, join() est pour attendre qu'un autre thread termine son exécution, et interrupt() est pour interrompre un thread en cours d'exécution pour faire autre chose.

 2
Author: abbas, 2014-08-04 12:56:22

Les réponses actuelles sont obsolètes et nécessitent une révision compte tenu des changements récents.

Il n'y a pas de pratique différence de Thread.yield() entre les versions Java depuis 6 à 9.

TL;DR;

Conclusions basées sur le code source OpenJDK (http://hg.openjdk.java.net/).

Si ne pas prendre en compte la prise en charge des hotspots des sondes USDT (les informations de suivi du système sont décrites dans dtrace guide ) et la propriété JVM ConvertYieldToSleep alors le code source de yield() est presque le même. Voir l'explication ci-dessous.

Java 9:

Thread.yield() appelle la méthode spécifique au système d'exploitation os::naked_yield():
Sous Linux:

void os::naked_yield() {
    sched_yield();
}

Sous Windows:

void os::naked_yield() {
    SwitchToThread();
}

Java 8 et versions antérieures:

Thread.yield() appelle la méthode spécifique au système d'exploitation os::yield():
Sous Linux:

void os::yield() {
    sched_yield();
}

Sous Windows:

void os::yield() {  os::NakedYield(); }

Comme vous pouvez le voir, Thread.yeald() sous Linux est identique pour toutes les versions de Java.
Voyons les fenêtres os::NakedYield() de JDK 8:

os::YieldResult os::NakedYield() {
    // Use either SwitchToThread() or Sleep(0)
    // Consider passing back the return value from SwitchToThread().
    if (os::Kernel32Dll::SwitchToThreadAvailable()) {
        return SwitchToThread() ? os::YIELD_SWITCHED : os::YIELD_NONEREADY ;
    } else {
        Sleep(0);
    }
    return os::YIELD_UNKNOWN ;
}

La différence entre Java 9 et Java 8 dans la vérification supplémentaire de l'existence de la méthode SwitchToThread() de l'API Win32. Le même code est présent pour Java 6.
Le code source de os::NakedYield() dans JDK 7 est légèrement différent mais il a le même comportement:

    os::YieldResult os::NakedYield() {
    // Use either SwitchToThread() or Sleep(0)
    // Consider passing back the return value from SwitchToThread().
    // We use GetProcAddress() as ancient Win9X versions of windows doen't support SwitchToThread.
    // In that case we revert to Sleep(0).
    static volatile STTSignature stt = (STTSignature) 1 ;

    if (stt == ((STTSignature) 1)) {
        stt = (STTSignature) ::GetProcAddress (LoadLibrary ("Kernel32.dll"), "SwitchToThread") ;
        // It's OK if threads race during initialization as the operation above is idempotent.
    }
    if (stt != NULL) {
        return (*stt)() ? os::YIELD_SWITCHED : os::YIELD_NONEREADY ;
    } else {
        Sleep (0) ;
    }
    return os::YIELD_UNKNOWN ;
}

La vérification supplémentaire a été supprimée en raison de SwitchToThread()la méthode est disponible depuis Windows XP et Windows Server 2003 (voir msdn notes).

 2
Author: Gregory.K, 2018-01-13 14:42:29

Thread.yield() fait passer le thread de l'état" en cours d'exécution "à l'état" Exécutable". Remarque: Cela ne provoque pas l'état "Attente" du thread.

 0
Author: Prashant Gunjal, 2017-05-05 18:16:03

Fil.rendement()

Lorsque nous invoquons Fil.méthode yield (), le planificateur de threads maintient le thread en cours d'exécution à l'état Runnable et choisit un autre thread de priorité égale ou supérieure. S'il n'y a pas de thread de priorité égale et supérieure, il replanifie le thread appelant yield (). Rappelez-vous que la méthode de rendement ne rend pas le thread à attendre ou bloqué. Il ne peut faire un thread de l'État en cours d'exécution à l'État Runnable.

Join ()

Lorsque join est invoqué par une instance de thread, ce thread dira au thread en cours d'exécution d'attendre que le thread de jointure se termine. Join est utilisé dans les situations où une tâche qui doit être terminée avant la tâche en cours va se terminer.

 -1
Author: Prashant Kumar, 2014-05-12 10:14:43

Yield() l'utilisation principale est de mettre une application multi-threading en attente.

Toutes ces différences de méthodes sont yield() met le thread en attente lors de l'exécution d'un autre thread et revient après l'achèvement de ce thread, join() amènera le début des threads ensemble s'exécutant jusqu'à la fin et d'un autre thread à exécuter après la fin de ce thread, interrupt() arrêtera l'exécution d'un

 -4
Author: K.Hughley, 2014-08-01 20:43:11