web-dev-qa-db-fra.com

Comment donner un nom à un fil appelable?

J'exécute un objet appelable à l'aide du pool de threads ExecutorService. Je veux donner un nom à ce fil.

Pour être plus précis, dans l'ancienne version, je l'avais fait -

Thread thread = new Thread(runnable Task);
thread.setName("My Thread Name");

J'utilise le nom du fil dans la journalisation log4j, cela aide beaucoup lors du dépannage. Maintenant, je migre mon code de Java 1.4 à Java 1.6. J'ai écrit ceci (Donné ci-dessous) - mais je ne sais pas comment donner un nom à ce fil.

private final ExecutorService executorPool = Executors.newCachedThreadPool();
Future<String> result = executorPool.submit(callable Task);

S'il vous plaît, donnez-moi une idée pour donner un nom à ce fil?

33
user381878

Vous pouvez utiliser la méthode surchargée:

Java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory)

ce qui vous permet de passer un 

Java.util.concurrent.ThreadFactory

cela devrait vous permettre de définir les noms du fil via Java.util.concurrent.ThreadFactory.newThread(Runnable):

Construit une nouvelle Thread. Les implémentations peuvent également initialiser la priorité, le nom, le statut du démon, ThreadGroup, etc.

Regardez Java.util.concurrent.Executors.DefaultThreadFactory pour une implémentation par défaut.

Addenda

Comme je vois que ce fil est toujours visité, Guava (si vous en avez un) fournit un ThreadFactoryBuilder qui tire parti de la nécessité de disposer d’une classe anonyme interne et permet même de personnaliser les noms paramétrés de vos threads.

29
Andreas

Je le fais actuellement un peu comme ceci:

    someExecutor.execute(new Runnable() {
        @Override public void run() {
            final String orgName = Thread.currentThread().getName();
            Thread.currentThread().setName(orgName + " - My custom name here");
            try {
                myAction();
            } finally {
                Thread.currentThread().setName(orgName);
            }
        }
    });
36
Bart van Heukelom
/**
 * The default thread factory
 */
static class DefaultThreadFactory implements ThreadFactory {
    static final AtomicInteger poolNumber = new AtomicInteger(1);
    final ThreadGroup group;
    final AtomicInteger threadNumber = new AtomicInteger(1);
    final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null)? s.getThreadGroup() :
                             Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" + 
                      poolNumber.getAndIncrement() + 
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, 
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

Ceci est l'implémentation d'origine dans Java 1.5.0. Ainsi, vous avez en réalité les noms de pool-x-thread, où x représente l’ordre du thread dans le groupe de thread actuel.

10
MT San

Soyez prudent lorsque vous renommez des threads lorsque ceux-ci sont gérés par un pool de threads, car ils sont en fait réutilisés à plusieurs reprises pour différentes tâches. Une fois renommés, vous constaterez que les noms de threads dans vos journaux n'ont aucun sens. ... Afin d'éviter ce comportement indésirable, vous devez vous assurer qu'une fois votre Runnable/Callable terminé, le nom du thread est restauré.

Une façon d'implémenter cela consiste à encapsuler chaque Runnable/Callable exécuté par le pool de threads avec un décorateur qui gère tous les nettoyages nécessaires.

8
Shai

Si vous utilisez Spring, vous pouvez utiliser org.springframework.scheduling.concurrent.CustomizableThreadFactory pour cela:

ExecutorService executorService = Executors.newCachedThreadPool(
                             new CustomizableThreadFactory("MyThreadNamePrefix"));
6
Konstantin Pavlov

Je devais faire ce que vous demandiez - fournir des noms à mes groupes de threads - alors, grâce à la réponse d'Andeas, j'ai créé mon propre ThreadFactory en tant que classe interne à la classe qui va l'utiliser en copiant Executors $ DefaultThreadFactory , en changeant 3 lignes en ajoutant le paramètre "nom du groupe" au constructeur. 

    /**
 * A thread factory that names each thread with the provided group name.
 * <p>
 * Except lines with "elarson modified", copied from code 
 * Executors$DefaultThreadFactory -- Doug Lea, Copyright Oracle, et al.
 */
static class GroupNameThreadFactory implements ThreadFactory {
    private String groupname; /* elarson modified */
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    GroupNameThreadFactory(String groupname) {
        this.groupname = groupname; /* elarson modified */
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                       this.groupname + /* elarson modified */
                       poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

La création d'un ThreadPool à partir de celui-ci se fait comme suit.

        ThreadFactory threadfactory = new GroupNameThreadFactory("Monitor");    
    executor = Executors.newFixedThreadPool(NUM_THREADS, threadfactory);

Merci à l'utilisateur381878 d'avoir posé la question et à Andreas pour la réponse.

2
Eric Larson

Créez simplement un ThreadFactory anonyme pour obtenir le service d’exécution . Le ThreadFactory peut fournir le nom du thread comme suit: "Thread A" ou "Thread B" (voir l’exemple).

Appelez ensuite la tâche appelable à l’aide des différents services de l’exécuteur:

Exemple de classe:

classe publique ThreadTester {

public static void main(String[] args) {
    ThreadTester threadTester = new ThreadTester();
    threadTester.test();
}

private void test() {

    ExecutorService executorservice = Executors.newCachedThreadPool(new ThreadFactory() {

        @Override
        public Thread newThread(Runnable arg0) {
            return new Thread(arg0,"Thread A");
        }
    });

    CallableTask taskA = new CallableTask();
    executorservice.submit(taskA);

    executorservice = Executors.newCachedThreadPool(new ThreadFactory() {

        @Override
        public Thread newThread(Runnable arg0) {
            return new Thread(arg0,"Thread B");
        }
    });
    CallableTask taskB = new CallableTask();
    executorservice.submit(taskB);
}

}

Tâche appelable:

la classe publique CallableTask implémente Callable {

@Override
public Integer call() throws Exception {
    int sum = 0;

    for(int count=1;count<=30;count++){
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " Count :"+count);
        sum = sum + count;
    }
    System.out.println(Thread.currentThread().getName() + " Sum :"+sum);
    return sum;
}

}

0
Nipin P

Une approche que j’ai utilisée, et dans mon cas, j’ai eu un certain nombre d’avenir recherchant des données en parallèle contrôlées par une seule classe. Je soumets un certain nombre d'emplois et récupère l'avenir. Je stocke le futur dans une carte avec la valeur comme nom de travail . Puis plus tard, lorsque je fais un get avec un dépassement de délai sur tous les futurs, j'ai le nom du travail de la carte. Ce n'est peut-être pas le moyen le plus flexible mais cela a fonctionné dans ma situation.

0