112 votes

Quelles sont les principales utilisations de rendement () et en quoi diffèrent-elles 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 aussi lu que le rendement() est "utilisé pour empêcher l'exécution d'un thread'.

Mes questions sont les suivantes:

  1. Je crois que le code ci-dessous produit le même résultat à la fois lors de l'utilisation d' yield() , et quand ne pas utiliser. Est-ce correct?

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

  3. En quoi est - yield() différente de l' 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();
      }
   }
}

Je obtenir le même résultat à l'aide du code ci-dessus à la fois avec et sans l'aide d' yield():

Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run

101voto

Sathwick Points 641

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

Windows

Dans le Hotspot de la mise en œuvre, à la manière de ce Thread.rendement() fonctionne a changé entre Java 5 et la version 6 de Java.

En Java 5, Fil.rendement() appelle l'appel d'API Windows Sleep(0). Cette a l'effet spécial de compensation le thread courant du quantum et de la le mettre à la fin de la file d'attente pour son niveau de priorité. Dans d'autres les mots, tous les exécutables, les threads de même priorité (et ceux de plus de priorité) va avoir une chance de s'exécuter avant le donné de fil est à côté compte tenu du temps de calcul. Quand il est finalement re-programmée, elle va revenir avec un plein complet quantique, mais n'a pas de "report" de la reste quantique à partir du moment de céder. Ce comportement est un peu différente de zéro, le sommeil où le thread en sommeil généralement perd 1 quantique valeur (en effet, 1/3 de 10 ou 15ms tique).

Dans la version 6 de Java, ce comportement a été modifié. Le Hotspot VM implémente maintenant Fil de discussion.rendement() à l'aide de la Windows SwitchToThread() appel d'API. Cet appel fait le thread en cours d'abandonner son actuel timeslice, mais pas de son toute quantique. Cela signifie que selon les priorités des autres threads, le rendement de filetage peut être prévue de retour dans une interruption période ultérieure. (Voir la section sur la planification de thread pour plus d' informations sur timeslices.)

Linux

Sous Linux, Hotspot appelle simplement sched_yield(). Les conséquences de cet appel sont un peu différentes, et peut-être plus grave que, en vertu de Windows:

  • un donné de fil ne sera pas obtenir une autre tranche de PROCESSEUR jusqu'à ce que tous les autres threads ont eu une tranche de CPU;
  • (au moins dans le noyau 2.6.8 à partir), le fait que le thread a donné est implicitement pris en compte par l'ordonnanceur de l'heuristique sur sa récente allocation PROCESSEUR - donc, implicitement, un thread qui a donné pourrait être donné plus de CPU lors de la planification à l'avenir.

(Voir la section sur la planification de thread pour plus de détails sur les priorités et les algorithmes d'ordonnancement.) Quand utiliser yield()?

Je dirais pratiquement jamais. Son comportement n'est pas correctement défini et il y a généralement de meilleurs moyens pour effectuer les tâches que vous souhaiterez peut-être effectuer avec un rendement():

  • si vous essayez d'utiliser une partie seulement de la CPU, vous pouvez le faire en plus de manière contrôlable par l'estimation de la quantité de CPU le thread a utilisé dans son dernier bloc de traitement, puis de couchage pour certains quantité de temps pour compenser: voir la méthode de sommeil ();
  • si vous êtes en attente d'un processus ou d'une ressource de compléter ou de devenir disponible, il y a des moyens plus efficaces pour ce faire, en utilisant par exemple des join() pour attendre un autre thread pour terminer, à l'aide de wait/notify mécanisme pour permettre à un fil pour le signal à l'autre qu'une tâche est terminée, ou, idéalement, en utilisant l'une des Java 5 la simultanéité de constructions comme un Sémaphore ou le blocage de la file d'attente.

44voto

Tudor Points 39539

Je vois que la question a été réactivée avec un bounty, demande maintenant à ce que les utilisations pratiques pour yield . Je vais vous donner un exemple tiré de mon expérience.

Comme nous le savons, yield forces le thread appelant à abandonner le processeur qu'il est en cours d'exécution sur un autre thread peut être programmé pour s'exécuter. Ceci est utile lorsque le thread courant a achevé son travail pour le moment, mais veut revenir rapidement à l'avant de la file d'attente et de vérifier si une certaine condition a changé. Comment est-ce différent d'une variable de condition? yield permet le fil de retour beaucoup plus rapide à l'exécution d'un état. 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 en gros "permettre à un autre thread à exécuter, mais permettez-moi de vous remettre au travail très vite que j'attends quelque chose à changer dans mon état, très très vite". Cela nous amène vers occupée à filer, un état qui peut changer rapidement, mais de suspendre le fil subirait un grand gain de performance.

Mais trêve de babillage, voici un exemple concret: le front d'onde modèle parallèle. De base d'une instance de ce problème est le calcul des "îlots" de 1s dans un tableau bidimensionnel rempli avec des 0 et des 1. Une "île" est un groupe de cellules qui sont adjacentes à l'autre à la verticale ou à l'horizontale:

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 1s: haut-gauche et bas-droite.

Une solution simple est de faire une première passe sur l'ensemble de la pile et remplacez le 1 valeurs avec une incrémentation du compteur de sorte qu'à la fin de chaque 1 a été remplacé par son numéro de séquence dans la ligne principale commande:

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

Dans l'étape suivante, chaque valeur est remplacé par le minimum entre lui-même et ses voisins valeurs:

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

Nous pouvons maintenant déterminer facilement 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 trop entrer dans les détails, chaque thread obtient les lignes de façon entrelacée et s'appuie sur les valeurs calculées par le thread de traitement de la ligne ci-dessus. Ainsi, chaque thread doit légèrement à la traîne derrière le thread de traitement de la ligne précédente, mais doit également se tenir dans un délai raisonnable. Plus de détails et une mise en œuvre sont présentés par moi-même dans le présent document. Remarque l'utilisation de l' sleep(0) ce qui est plus ou moins le C équivalent de yield.

Dans ce cas - yield a été utilisé pour forcer chaque thread à son tour de faire une pause, mais depuis le thread de traitement de la côté ligne de progresser très rapidement dans le temps, une variable de condition serait un choix désastreux.

Comme vous pouvez le voir, yield est assez fine-grain d'optimisation. L'aide dans le mauvais lieu, par exemple en attente sur la condition que les modifications n', seront la cause de l'utilisation excessive du CPU.

Désolé pour le long bavardage, de l'espoir, je me suis fait clair.

14voto

einpoklum Points 2893

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

  1. rendement: Littéralement, de "rendement" moyen de lâcher, abandonner, d'abandonner. Un rendement de filetage indique le système d'exploitation (ou de la machine virtuelle, ou ne pas) il est prêt à laisser les autres threads être planifiée en tenant lieu. Cela indique qu'il n'est pas de faire quelque chose de trop critique. C'est seulement un indice, cependant, et pas la garantie d'avoir un effet quelconque.
  2. joindre: Lorsque plusieurs threads "rejoindre" sur certains manipulent, ou un jeton, ou de l'entité, tous d'eux d'attendre jusqu'à ce que tous les autres threads ont terminé l'exécution, en tout ou jusqu'à leur propre correspondant jointure). Que signifie un tas de fils ont tous terminé leurs tâches. Ensuite, chacun de ces threads peuvent être planifiés pour poursuivre d'autres travaux, d'être en mesure d'assumer toutes ces tâches sont en fait complète. (À ne pas confondre avec les Jointures SQL!)
  3. interruption: Utilisé par un seul thread à "pousser" un autre thread qui est du sommeil, ou d'attente, ou de se joindre, de sorte qu'il est prévu de continuer à fonctionner de nouveau, avec peut-être une indication qu'il a été interrompu. (À ne pas confondre avec les interruptions matérielles!)

Pour Java en particulier, consultez

  1. Joindre:

    Comment utiliser Thread.rejoindre? (ici sur StackOverflow)

    Lorsque les pour rejoindre les threads?

  2. Rendement:

  3. Interrompre:

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

10voto

MByD Points 78505

Tout d'abord, la description réelle est

Causes le thread en cours d'exécution de l'objet pour interrompre temporairement la lecture et permettre à d'autres threads.

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

join va arrêter le thread courant jusqu'à ce que le thread qui est appelée avec join() est effectuée en cours d'exécution.

interrupt va interrompre le fil, elle est appelée, provoquant InterruptedException.

yield permet à un changement de contexte pour les autres threads, de sorte que ce fil ne sera pas consommer l'intégralité de l'utilisation du PROCESSEUR du processus.

0voto

EJP Points 113412

1.Avec et avec l'aide de méthode de rendement dans le soufflet code de la même les résultats sont obtenus. Est-il correct?

Le bon de sortie dans ce cas n'est pas spécifié si tout est correct.

2.En fait, ce est l'utilisation principale de rendement()

Il est rarement utilisé, et encore moins suffisante pour identifier un "principal". Je n'ai jamais utilisé un rendement() la méthode sur toute plate-forme, et j'ai eu à ma disposition depuis plus de 20 ans, et je me suis engagé dans très sérieux au système de programmation sur l'ensemble de la période.

3.Comment il est différent de join() et de l'interruption() méthodes

Il est différent en ce qu'il n'est pas le même. La question est complètement dénuée de sens.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X