Comment obtenir l'ID de thread d'un pool de threads?

131

J'ai un pool de threads fixe auquel je soumets des tâches (limité à 5 threads). Comment puis-je savoir lequel de ces 5 threads exécute ma tâche (quelque chose comme "thread n ° 3 sur 5 fait cette tâche")?

ExecutorService taskExecutor = Executors.newFixedThreadPool(5);

//in infinite loop:
taskExecutor.execute(new MyTask());
....

private class MyTask implements Runnable {
    public void run() {
        logger.debug("Thread # XXX is doing this task");//how to get thread id?
    }
}
serg
la source

Réponses:

230

Utilisation Thread.currentThread():

private class MyTask implements Runnable {
    public void run() {
        long threadId = Thread.currentThread().getId();
        logger.debug("Thread # " + threadId + " is doing this task");
    }
}
skaffman
la source
3
ce n'est en fait pas la réponse souhaitée; on devrait utiliser à la % numThreadsplace
petrbel
2
@petrbel Il répond parfaitement au titre de la question, et le thread id est assez proche à mon avis quand l'OP demande "quelque chose comme 'thread # 3 sur 5".
CorayJeu
Notez, un exemple de sortie de getId()est 14291où comme getName()vous le donne pool-29-thread-7, ce qui, à mon avis, est plus utile.
Joshua Pinter
26

La réponse acceptée répond à la question sur l'obtention d' un identifiant de thread, mais elle ne vous permet pas de faire des messages "Thread X of Y". Les identifiants de threads sont uniques entre les threads mais ne commencent pas nécessairement par 0 ou 1.

Voici un exemple correspondant à la question:

import java.util.concurrent.*;
class ThreadIdTest {

  public static void main(String[] args) {

    final int numThreads = 5;
    ExecutorService exec = Executors.newFixedThreadPool(numThreads);

    for (int i=0; i<10; i++) {
      exec.execute(new Runnable() {
        public void run() {
          long threadId = Thread.currentThread().getId();
          System.out.println("I am thread " + threadId + " of " + numThreads);
        }
      });
    }

    exec.shutdown();
  }
}

et la sortie:

burhan@orion:/dev/shm$ javac ThreadIdTest.java && java ThreadIdTest
I am thread 8 of 5
I am thread 9 of 5
I am thread 10 of 5
I am thread 8 of 5
I am thread 9 of 5
I am thread 11 of 5
I am thread 8 of 5
I am thread 9 of 5
I am thread 10 of 5
I am thread 12 of 5

Un léger ajustement en utilisant l'arithmétique modulo vous permettra de faire correctement "thread X of Y":

// modulo gives zero-based results hence the +1
long threadId = Thread.currentThread().getId()%numThreads +1;

Nouveaux résultats:

burhan@orion:/dev/shm$ javac ThreadIdTest.java && java ThreadIdTest  
I am thread 2 of 5 
I am thread 3 of 5 
I am thread 3 of 5 
I am thread 3 of 5 
I am thread 5 of 5 
I am thread 1 of 5 
I am thread 4 of 5 
I am thread 1 of 5 
I am thread 2 of 5 
I am thread 3 of 5 
Burhan Ali
la source
5
Les ID de thread Java sont-ils garantis contigus? Sinon, votre modulo ne fonctionnera pas correctement.
Brian Gordon
@BrianGordon Pas sûr d'une garantie, mais le code ne semble rien de plus que d'incrémenter un compteur interne: hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/…
Burhan Ali
6
Ainsi, si deux pools de threads étaient initialisés simultanément, les threads de l'un de ces pools de threads pourraient avoir des ID de, par exemple, 1, 4, 5, 6, 7 et dans ce cas, vous auriez deux threads différents avec le même "Je suis fil n de message de 5 ".
Brian Gordon le
@BrianGordon Thread.nextThreadID () est synchronisé, donc ce ne serait pas un problème, non?
Matheus Azevedo
@MatheusAzevedo Cela n'a rien à voir avec ça.
Brian Gordon
6

Vous pouvez utiliser Thread.getCurrentThread.getId (), mais pourquoi voudriez-vous faire cela alors que les objets LogRecord gérés par le logger ont déjà l'ID de thread. Je pense qu'il vous manque une configuration quelque part qui enregistre les ID de thread pour vos messages de journal.

Vineet Reynolds
la source
1

Si votre classe hérite de Thread , vous pouvez utiliser des méthodes getNameet setNamenommer chaque thread. Sinon, vous pouvez simplement ajouter un namechamp à MyTasket l'initialiser dans votre constructeur.

Justin Ethier
la source
1

Si vous utilisez la journalisation, les noms de threads seront utiles. Une fabrique de fil vous aide à cela:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class Main {

    static Logger LOG = LoggerFactory.getLogger(Main.class);

    static class MyTask implements Runnable {
        public void run() {
            LOG.info("A pool thread is doing this task");
        }
    }

    public static void main(String[] args) {
        ExecutorService taskExecutor = Executors.newFixedThreadPool(5, new MyThreadFactory());
        taskExecutor.execute(new MyTask());
        taskExecutor.shutdown();
    }
}

class MyThreadFactory implements ThreadFactory {
    private int counter;
    public Thread newThread(Runnable r) {
        return new Thread(r, "My thread # " + counter++);
    }
}

Production:

[   My thread # 0] Main         INFO  A pool thread is doing this task
Vitaliy Polchuk
la source
1

Il existe un moyen pour le thread actuel d'obtenir:

Thread t = Thread.currentThread();

Une fois que vous avez obtenu l'objet de classe Thread (t), vous pouvez obtenir les informations dont vous avez besoin en utilisant les méthodes de classe Thread.

Obtention de l'ID de fil:

long tId = t.getId(); // e.g. 14291

Obtention du nom du fil:

String tName = t.getName(); // e.g. "pool-29-thread-7"
Serg.Stankov
la source