10
votes

Avec ThreadPoolEcutor, comment obtenir le nom du fil en cours d'exécution dans la piscine de thread?

J'utilise un threadpoolEcutor en Java pour gérer beaucoup de threads en cours d'exécution. J'ai créé mon propre simple TrainFactory afin que je puisse donner aux threads meilleurs noms.

Le problème est que le nom est défini dans le fil lorsque le pool de threads est créé et n'est pas lié à la tâche que la piscine de thread est en cours d'exécution. Je comprends cela ... mes runnables et mes callables - bien qu'ils aient des noms - sont en réalité un niveau d'abstraction en baisse de la threadpoolEcutor S exécutant des threads.

Il y a eu d'autres questions sur Stackoverflow sur la création de noms pour threadpoolexecutor piscines de fil. (Voir Comment donner un nom à un fil appelable? et Comment nommer les discussions d'une piscine de fil dans Java .)

Ce que je veux savoir est: Quelqu'un a-t-il une bonne solution pour garder le nom du fil de piscine de thread en synchronisation avec l'exécution de celle-ci?

I.e. Si j'appelle thread.getCurrentThread (). GetName () Je l'aimerais pas pour renvoyer le nom de la piscine de thread de niveau supérieur, mais plutôt le nom de la Appelable / runnable que le thread est en cours d'exécution.

Étant donné que cela concerne principalement le débogage et la journalisation, j'essaie d'éviter une solution qui implique de mettre un nouveau code dans chaque runnable qui pourrait être soumise au threadpoolexecutor - Je préfère simplement mettre du code dans la filefactoire ou enveloppez la threadpoolexecutor elle-même afin que le changement soit effectué au même endroit. Si une telle solution n'existe pas, je ne vais probablement pas déranger car ce n'est pas critique de mission.

commencez à modifier pour clarifier, je sais que je peux mettre un fil.CurrentTthread (). SetName ("Mon nom annulable"); En tant que première ligne de chaque méthode de course d'exécution, mais j'essaie d'éviter de le faire. Je suis un perfectionniste ici, et je le réalise, donc je ne serai pas offensé si les gens veulent commenter cette question et me le dire. fin d'édition

Mon autre question, je suppose, est de savoir si les gens pensent que c'est une mauvaise idée de faire une telle chose. Devrais-je me méfier de mettre à jour le nom de la piscine de thread comme celui-ci?

Merci pour toute suggestion!


3 commentaires

"Garder le nom du filetage de la piscine de thread en synchronisation avec l'exécutable qu'il est en cours d'exécution" -> Runnable / appelable ne définit pas un nom, je ne peux donc pas voir la poussée de votre question. Votre filefactory donne-t-il réellement un nom distinct un nom distinct?


Droite, chacun de mes runnables et des appelables implémenter une interface nommée, alors j'ai accès à des noms. Je me rends compte que je suis difficile dans lequel j'ai déjà implémenté une fonctionnalité spéciale pour tous mes runnables, mais je veux éviter d'ajouter du code supplémentaire qui définit manuellement le nom du thil.


Édité pour plus de clarté, modifiant une "piscine de thread" sur "thread" et un "fil" à "tâche".


3 Réponses :


3
votes

Ma suggestion serait d'essayer xxx

Vous pouvez également réinitialiser le nom lorsque vous avez terminé si vous le souhaitez.


2 commentaires

Vous suggérez-vous que je fais cela chaque fois que je fais un appel à la piscine.execute ou que je remplace la méthode d'exécution de la piscine?


En supposant que vous souhaitez modifier le nom pour refléter le ce que ce thread est en train de faire, oui. Remarque: il changera lorsque le runnable démarre, non pas lorsque vous appelez invoke. ;)



15
votes

Créer un threadpoolexecutor qui remplace la méthode BeforeExecute.

/**
 * Method invoked upon completion of execution of the given Runnable.
 * This method is invoked by the thread that executed the task. If
 * non-null, the Throwable is the uncaught <tt>RuntimeException</tt>
 * or <tt>Error</tt> that caused execution to terminate abruptly.
 *
 * <p><b>Note:</b> When actions are enclosed in tasks (such as
 * {@link FutureTask}) either explicitly or via methods such as
 * <tt>submit</tt>, these task objects catch and maintain
 * computational exceptions, and so they do not cause abrupt
 * termination, and the internal exceptions are <em>not</em>
 * passed to this method.
 *
 * <p>This implementation does nothing, but may be customized in
 * subclasses. Note: To properly nest multiple overridings, subclasses
 * should generally invoke <tt>super.afterExecute</tt> at the
 * beginning of this method.
 *
 * @param r the runnable that has completed.
 * @param t the exception that caused termination, or null if
 * execution completed normally.
 */
protected void afterExecute(Runnable r, Throwable t) { }


10 commentaires

J'essaie réellement quelque chose comme ça maintenant, une bonne suggestion. Le seul problème est que la finalisation est complète, la piscine de thread a toujours ce nom. Malheureusement, la méthode postérieure ultérieure ne reçoit pas le fil dans lequel le courant est exécuté. J'aimerais pouvoir le nettoyer quand j'aurai fini aussi.


@JEFFEFFGLOLDBERG À AfterExecute, le thread.CurrentThread () est en réalité le fil que je définit le nom de Beforeexecute. Je mettrai à jour ma réponse pour démontrer cela.


Génial c'est génial. Merci!


J'ai fait un ajustement, et c'était pour ajouter un mappe OriginalTheadNamemap afin que je puisse réinitialiser le thread à son nom d'origine dans la méthode méthode , mais C'est lié à la manière dont mon programme spécifique nomme des threads. Quoi qu'il en soit, cela fonctionne très bien et je l'aime plus que remplacer la méthode d'exécution et il semble plus propre que d'envelopper dans une nouvelle runnable. Merci de votre aide et merci de lire le Javadoc plus près que prévu.


Aucun problème! Assurez-vous que vous utilisez un ConcurrentMap :) sinon vous pouvez rencontrer une boucle infinie! mailinator.blogspot.com/2009/06/Beautiful-race-condition. htm l


J'ai rencontré suffisamment de conditions de course dans ce système que je l'aurais déjà mis dans une carte synchronisée. Puisque je fais seulement des puts et supprime, il n'y a aucun avantage d'avoir les lectures rapides de ConcurrentMap. En outre, j'adore cet article que vous avez lié ... comme son auteur, moi aussi je suis toujours étrangement excité lorsque je découvre une condition de course.


Dans la réponse, il y a une question: "Je ne sais pas comment exactement DeriverunnaBename () fonctionnerait, peut-être tostring ()?". TOSTRING () ne semble pas fonctionner et que le fichier runnable dans BeforeExecute () n'est pas identique à celui que je suis passé à soumettre () Je ne sais pas comment accéder au nom d'origine des runnables.


@Zitrax Le DeriverunnaBename est vraiment spécifique à la mise en œuvre de l'exécution. Par exemple, si dans votre exécution, vous remplacez la méthode tostring que vous obtiendriez le nom que vous attendiez


@Johnvint que j'ai fait remplacement de Tostring (), mais quand je débogé, je peux voir que le runnable que je soumets n'est pas ce que je vois dans beforeexecute () . Dans beforeexecute () il imprime java.util.concurrent.threadpoolexecutenter$worker@4516ee8c [stat e = -1, file d'attente vide] dans Soumettre () Impression de mon Tostring () Mise en œuvre. Je suppose donc que la mise en œuvre interne enveloppe mon exécutable dans un travailleur, à partir de laquelle mon original annulable n'est pas exposé.


@ZiTRAX, vous avez raison que le TPE enveloppera la runnable dans un futuretask. Je mettrai à jour ma réponse pour supporter Tostring



4
votes

Donc, j'ai une solution qui gère les deux pour définir le nom et nettoyer après le nom. Merci à Peter Lawrey et John Vint pour leurs suggestions qui m'ont conduit ici. Étant donné que ni la suggestion ne manipulait pleinement mon problème, je pensais que je posterais ce code d'exemple comme une réponse distincte. Je m'excuse si c'est pauvre étiquette - si oui, laissez-moi savoir et je vais vous ajuster.

Dans le code ci-dessous, j'ai décidé de conserver le nom du thread de threadpoolEcutor d'origine et appendez le nom exécutable, puis dans le rejet enfin Le nom annulable pour nettoyer, mais cela peut être facilement modifié. p>

Comme John Vint suggère, je préférerais remplacer la méthode BeforeExecution code>, puis remplacer la méthode après -execution code> pour nettoyer, mais le Afterexecution code> n'a pas de poignée sur le fil. P>

public class RunnableNameThreadPoolExecutor extends ThreadPoolExecutor {

    /* Constructors... */

    @Override
    public void execute(Runnable command) {
        super.execute(new ManageNameRunnable(command));
    }

    private class ManageNameRunnable implements Runnable {
        private final Runnable command;
        ManageNameRunnable( Runnable command ) {
            this.command = command;
        }

        public void run() {
            String originalName = Thread.currentThread().getName();
            try {
                String runnableName = getRunnableName(command);
                Thread.currentThread().setName(originalName+ ": " + runnableName);
                command.run();
            } finally {
                Thread.currentThread().setName(originalName);
            }
        }
    }
}


1 commentaires

Avez-vous plus de code de travail? Telle que GetRunnaBename () Définition et exemple de code d'appel?