Bagaimana cara mendapatkan id utas dari kumpulan utas?

131

Saya memiliki kumpulan utas tetap yang saya ajukan tugas (terbatas pada 5 utas). Bagaimana saya bisa mengetahui salah satu dari 5 utas yang menjalankan tugas saya (sesuatu seperti "utas # 3 dari 5 melakukan tugas ini")?

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
sumber

Jawaban:

230

Menggunakan Thread.currentThread():

private class MyTask implements Runnable {
    public void run() {
        long threadId = Thread.currentThread().getId();
        logger.debug("Thread # " + threadId + " is doing this task");
    }
}
skaffman
sumber
3
ini sebenarnya bukan jawaban yang diinginkan; seseorang harus menggunakan % numThreadssebagai gantinya
petrbel
2
@petrbel Dia menjawab judul pertanyaan dengan sempurna, dan id utas cukup dekat menurut saya ketika OP meminta "sesuatu seperti 'utas # 3 dari 5".
CorayThan
Catatan, output contoh getId()adalah 14291dimana getName()memberikan pool-29-thread-7, yang saya berpendapat lebih berguna.
Joshua Pinter
26

Jawaban yang diterima menjawab pertanyaan tentang mendapatkan sebuah benang id, tetapi tidak membiarkan Anda melakukan "Thread X dari Y" pesan. Id utas unik di seluruh utas tetapi tidak harus dimulai dari 0 atau 1.

Ini adalah contoh yang cocok dengan pertanyaan:

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();
  }
}

dan hasilnya:

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

Tweak sedikit menggunakan modulo arithmetic akan memungkinkan Anda untuk melakukan "thread X of Y" dengan benar:

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

Hasil baru:

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
sumber
5
Apakah ID utas Java dijamin bersebelahan? Jika tidak, modulo Anda tidak akan berfungsi dengan benar.
Brian Gordon
@BrianGordon Tidak yakin tentang jaminan, tetapi kode tersebut tampaknya tidak lebih dari penambahan penghitung internal: hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/…
Burhan Ali
6
Jadi jika dua kumpulan utas diinisialisasi secara bersamaan, utas di salah satu utas tersebut mungkin memiliki ID, misalnya, 1, 4, 5, 6, 7 dan dalam hal ini Anda akan memiliki dua utas berbeda dengan yang sama "Saya utas n dari 5 "pesan.
Brian Gordon
@BrianGordon Thread.nextThreadID () disinkronkan, jadi ini tidak akan menjadi masalah, kan?
Matheus Azevedo
@MatheusAzevedo Itu tidak ada hubungannya dengan itu.
Brian Gordon
6

Anda dapat menggunakan Thread.getCurrentThread.getId (), tetapi mengapa Anda ingin melakukan itu ketika objek LogRecord dikelola oleh logger sudah memiliki id utas. Saya pikir Anda kehilangan konfigurasi di suatu tempat yang mencatat Id thread untuk pesan log Anda.

Vineet Reynolds
sumber
1

Jika kelas Anda mewarisi dari Thread , Anda dapat menggunakan metode getNamedan setNameuntuk memberi nama setiap thread. Kalau tidak, Anda bisa menambahkan namebidang MyTask, dan menginisialisasi dalam konstruktor Anda.

Justin Ethier
sumber
1

Jika Anda menggunakan logging maka nama utas akan membantu. Pabrik utas membantu dalam hal ini:

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++);
    }
}

Keluaran:

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

Ada cara mendapatkan utas saat ini:

Thread t = Thread.currentThread();

Setelah Anda mendapatkan objek kelas Thread (t) Anda bisa mendapatkan informasi yang Anda butuhkan menggunakan metode kelas Thread.

Mendapatkan ID thread:

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

Nama uttting:

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