35 votes

Méthode onSpinWait () de la classe Thread

Lors de l'apprentissage de Java 9, je suis tombé sur une nouvelle méthode de Thread classe, appelés onSpinWait​. Selon la documentation javadoc, cette méthode est utilisée pour ceci:

Indique que l'appelant est momentanément incapable de progrès, jusqu'à ce que le l'apparition d'une ou plusieurs actions de la part d'autres activités.

Quelqu'un peut-il m'aider à comprendre cette méthode donnant un exemple concret?

29voto

David Haim Points 3696

C'est la même chose (et probablement compilé) le x86 opcode PAUSE et équivalent Win32 macro YieldProcessor, de GCC __mm_pause() et la méthode C# Thread.SpinWait

C'est un très affaibli forme de rendement: c'est à propos de dire à votre CPU que vous êtes dans une boucle qui peut brûler un peu assez de CPU-cycles attendre que quelque chose arrive (occupé en attente).

De cette façon, Le CPU peut affecter plus de ressources à d'autres threads, sans réellement le chargement de l'OS planificateur et la file d'attente d'un thread en sommeil (ce qui peut être coûteux).

une utilisation courante est que le spin-verrouillage, quand vous savez que la contention sur une mémoire partagée est très peu fréquents ou des finitions très rapidement, un spinlock peut préforme mieux qu'une simple serrure.

Pseudo code pour peut ressembler à:

int state = 0; //1 - locked, 0 - unlocked

routine lock:
    while cas(state, 1) == 1
       yield

routine unlock:
    atomic_store(state,0)

yield peut être mis en œuvre en termes de Thread.onSpinWait(), laissant entendre que tout en essayant de verrouillage de la serrure, le CPU peut donner plus de ressources à d'autres threads.

PS. cette technique de rendement est extrêmement fréquent et populaire lors de la mise en œuvre d'un lock-free algorithmes, puisque la plupart d'entre eux dépend occupé-attendre (ce qui est mis en œuvre presque toujours atomique CAS de la boucle). cela a chaque utilisation dans le monde réel que vous pouvez imaginer.

22voto

MouseEvent Points 3303

Pur système allusion!

La lecture de cet article je cite:

Objectifs

Définir une API qui permettrait de code Java à l'astuce pour l'exécution du système qu'il est en un tour de boucle. L'API sera un pur soupçon, et ne comportent pas de sémantique du comportement des exigences (par exemple, un no-op est valable de mise en œuvre). Permettre à la JVM de bénéficier de tourner la boucle de comportements spécifiques qui peuvent être utile sur certaines plates-formes matérielles. Fournir à la fois un no-op de la mise en œuvre et une valeur intrinsèque de la mise en œuvre dans le JDK, et de démontrer une exécution de la prestation, sur au moins une des principales plate-forme matérielle.

Il y a nombre de fois qu'un thread doit être suspendu jusqu'à ce que quelque chose en dehors de son champ d'application des modifications. Un (une) pratique courante était l' wait() notify() modèle où il y a un thread en attente pour l'autre thread pour les réveiller.

Il y a une grande limitation de cette, à savoir, l'autre thread doit être conscient qu'il pourrait y avoir des threads en attente et doivent en avertir. Si le travail de l'autre thread est en dehors de votre contrôle, il n'y a aucun moyen d'être averti.

Le seul moyen serait un spin-attendre. disons que vous avez un programme qui vérifie la présence de nouveaux e-mails et avertit l'utilisateur:

while(true) {
    while(!newEmailArrived()) {
    }
    makeNotification();
}

Ce bout de code va exécuter des millions de fois par secondes; la filature, à maintes reprises, à l'aide précieuse de l'électricité et de la puissance CPU. Une façon courante de le faire serait d'attendre quelques secondes à chaque itération.

while(true) {
    while(!newEmailArrived()) {
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) {
        }
    }
    makeNotification();
}

Ce qui fait un très bon travail. Mais dans le cas où vous avez à travailler instantanément un sommeil peut être hors de question.

Java 9 essaie de résoudre ce problème par l'introduction de cette nouvelle méthode:

while(true) {
    while(!newEmailArrived()) {
        Thread.onSpinWait();
    }
    makeNotification();
}

Cela fonctionne exactement la même que sans l'appel de la méthode, mais le système est gratuit pour abaisser la priorité du processus; le ralentissement du cycle ou de réduire l'électricité sur cette boucle, lorsque ses ressources sont nécessaires pour d'autres choses plus importantes.

9voto

igaz Points 168

Pour un exemple réel, supposons que vous vouliez mettre en œuvre asynchrone de journalisation, où les threads que voulez enregistrer quelque chose, vous ne voulez pas attendre pour leur message de journal pour obtenir "publié" (dire, écrire dans un fichier), juste aussi longtemps que il a finalement fait (parce qu'ils ont un réel travail à faire.)

Producer(s):
concurrentQueue.push("Log my message")

Et dire, vous décidez d'avoir un dédié thread consommateur, qui est le seul responsable pour écrire des messages dans un fichier log:

(Single)Consumer

while (concurrentQueue.isEmpty())
{
    //what should I do?

}
writeToFile(concurrentQueue.popHead());
//loop

La question est de savoir quoi faire dans l'intérieur de l'en bloc? Java n'a pas fourni de solution idéale: vous pourriez faire un Thread.sleep(), mais pour combien de temps et c'est lourd; ou d'un Fil.rendement(), mais c'est spécifié, ou vous pouvez utiliser un verrou ou d'un mutex*, mais c'est souvent trop lourd et ralentit les producteurs à la baisse (et vicie le but déclaré de l'asynchrone de journalisation).

Ce que vous voulez vraiment est-à-dire au moment de l'exécution, "je pense que je ne vais pas attendre trop longtemps, mais je tiens à minimiser les frais généraux en attente/effets négatifs sur d'autres threads". C'est là que le Fil de discussion.onSpinWait() est livré dans.

Comme une réponse ci-dessus indiqué, sur les plates-formes compatibles (comme x86), onSpinWait() obtient intrinsified en PAUSE d'instruction, qui vous donnera les avantages que vous voulez. Donc:

(Single)Consumer

while (concurrentQueue.isEmpty())
{
    Thread.onSpinWait();

}
writeToFile(concurrentQueue.popHead());
//loop

Il a été démontré empiriquement que cela peut améliorer la latence de "occupé-attendre" style de boucles.

Je tiens également à préciser que ce n'est pas seulement utile dans la mise en œuvre de "spin-serrures" (même si c'est vraiment utile dans une telle circonstance); le code ci-dessus ne nécessite pas de verrouillage de spin (ou autre) de toute nature.

Si vous souhaitez vous lancer dans les mauvaises herbes, vous ne pouvez pas faire mieux que Intel specs

*Pour plus de clarté, la JVM est incroyablement intelligent, dans une tentative de minimiser le coût de mutex, et utilisera léger serrures début, mais c'est un autre débat.

7voto

Eugene Points 6271

Je veux juste ajouter que mes 2 cents après avoir lu le document et le code source. Cette méthode pourrait déclencher quelques optimisations et peut-pas - si les soins doivent être prises: vous ne pouvez pas vraiment compter sur elle - depuis cette hint de la CPU de plus que la demande, il y a probablement aucun initiale en invoquant que ce soit, de toute façon... ce qui Signifie que c'est vrai code source ressemble à ceci:

@HotSpotIntrinsicCandidate
public static void onSpinWait() {}

Ce que cela signifie réellement, c'est que cette méthode est en fait un NO-OP jusqu'à ce qu'il frappe l' c2 compiler dans la JIT, selon ce

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