Dapatkan daftar semua utas yang saat ini berjalan di Jawa


232

Apakah ada cara saya bisa mendapatkan daftar semua thread yang sedang berjalan di JVM saat ini (termasuk utas yang tidak dimulai oleh kelas saya)?

Apakah mungkin untuk mendapatkan Threaddan Classobjek dari semua utas dalam daftar?

Saya ingin dapat melakukan ini melalui kode.

Jawaban:


325

Untuk mendapatkan perangkat yang dapat diubah:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();

19
Meskipun jauh lebih bersih daripada alternatif lain yang diusulkan, ini memiliki kerugian karena menimbulkan biaya untuk mendapatkan jejak tumpukan untuk semua utas. Jika Anda tetap akan menggunakan jejak tumpukan itu, ini jelas lebih unggul. Jika tidak, maka ini mungkin jauh lebih lambat karena tidak ada keuntungan selain kode bersih.
Eddie

29
@ Eddie Apakah itu asumsi dari akal sehat, atau apakah Anda melakukan percobaan? "secara signifikan lebih lambat" katamu; berapa lambat? Apakah itu layak? Saya mempertanyakan segala upaya untuk memperburuk kode demi efisiensi. Jika Anda memiliki persyaratan efisiensi dan infrastruktur untuk mengukur efisiensi secara kuantitatif, maka saya setuju dengan orang-orang yang memperburuk kode, karena mereka sepertinya tahu apa yang mereka lakukan. Lihat akar dari semua kejahatan menurut Donald Knuth.
thejoshwolfe

20
Saya belum menghitung waktu alternatif-alternatif spesifik ini, tetapi saya telah bekerja dengan cara Java lainnya untuk mengumpulkan jejak stack vs hanya daftar utas. Dampak kinerja tampaknya sangat bergantung pada JVM mana yang Anda gunakan (misalnya JRockit vs Sun JVM). Ini layak diukur dalam contoh spesifik Anda. Apakah itu akan mempengaruhi Anda atau tidak, tergantung pada pilihan JVM Anda dan pada berapa banyak utas yang Anda miliki. Saya menemukan bahwa mendapatkan semua jejak stack melalui ThreadMXBean.dumpAllThreads untuk sekitar 250 thread membutuhkan 150 - 200 msec sementara hanya mendapatkan daftar thread (tanpa jejak) agar tidak dapat diukur (0 msec).
Eddie

4
Pada sistem saya (Oracle Java 1.7 VM), pemeriksaan cepat menunjukkan bahwa metode ini ~ 70..80 kali lebih lambat dari alternatif di bawah ini. Jejak tumpukan dan refleksi milik operasi Jawa terberat.
Franz D.

5
@ thejoshwolfe: Tentu saja, keterbacaan adalah faktor penting, dan orang tidak boleh mengoptimalkan mikro dll. Namun, saya melakukan penelitian sambil menulis monitor kinerja aplikasi kecil. Untuk alat semacam ini, jejak kinerja minimal sangat penting untuk mendapatkan data yang andal, jadi saya memilih metode stacktrace-less.
Franz D.

75

Dapatkan pegangan ke root ThreadGroup, seperti ini:

ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parentGroup;
while ((parentGroup = rootGroup.getParent()) != null) {
    rootGroup = parentGroup;
}

Sekarang, panggil enumerate()fungsi pada grup root berulang kali. Argumen kedua memungkinkan Anda mendapatkan semua utas, secara rekursif:

Thread[] threads = new Thread[rootGroup.activeCount()];
while (rootGroup.enumerate(threads, true ) == threads.length) {
    threads = new Thread[threads.length * 2];
}

Perhatikan bagaimana kami memanggil enumerate () berulang kali hingga array cukup besar untuk memuat semua entri.


22
Saya terkejut bahwa strategi ini sangat populer di internet. Strategi saya lebih sederhana (1 baris kode) dan berfungsi dengan baik dengan bonus tambahan menghindari kondisi balapan.
thejoshwolfe

11
@ thejoshwolfe: Sebenarnya, saya setuju - saya pikir jawaban Anda jauh lebih baik, dan mungkin jawaban itu sudah diterima sejak awal jika tidak terlambat satu tahun. Jika OP masih sering mengunjungi SO, yang ternyata dia lakukan, dia akan disarankan untuk tidak menerima jawaban saya dan lebih baik menerima jawaban Anda.
Frerich Raabe

2
Perhatikan bahwa untuk hal lain selain rootGroup, Anda harus menggunakan new Thread[rootGroup.activeCount()+1]. activeCount()bisa menjadi nol, dan jika itu Anda akan mengalami loop tak terbatas.
jmiserez

7
@ thejoshwolfe Saya kira solusi ini jauh lebih murah.
Haozhun

19
+1 untuk jawaban yang diremehkan ini, karena jauh lebih cocok untuk keperluan pemantauan IMHO. Kondisi ras yang melekat tidak terlalu menjadi masalah dalam pemantauan. Namun, seperti yang ditunjukkan oleh beberapa tes cepat, ini sekitar 70-80 kali lebih cepat daripada solusi berbasis stacktrace. Untuk pemantauan, jejak kinerja kecil sangat penting, karena Anda ingin menjaga efek pada sistem yang dipantau sekecil mungkin (Heisenberg menyerang lagi :) Untuk debugging, di mana Anda mungkin memerlukan informasi yang lebih andal, metode stacktrace bisa menjadi penting. BTW, solusi MxBean bahkan lebih lambat daripada menggunakan stacktraces.
Franz D.

29

Ya, lihatlah untuk mendapatkan daftar utas . Banyak contoh di halaman itu.

Itu untuk melakukannya secara terprogram. Jika Anda hanya ingin daftar di Linux setidaknya Anda bisa menggunakan perintah ini:

kill -3 processid

dan VM akan melakukan thread dump ke stdout.


5
bunuh -3? Setidaknya di linux saya, itu "terminal berhenti". Tewaskan, tidak daftar.
Michael H.

5
cletus memang benar - kill -3 akan me-dump dump ke stdout, terlepas dari apa artinya sinyal. Saya akan mempertimbangkan menggunakan jstack sebagai gantinya.
Dan Hardiker

mendapatkan daftar utas tidak dapat dihubungi: nadeausoftware.com menolak untuk terhubung.
DSlomer64


14

Apakah Anda sudah melihat jconsole ?

Ini akan mencantumkan semua utas yang berjalan untuk proses Java tertentu.

Anda dapat memulai jconsole dari folder bin JDK.

Anda juga bisa mendapatkan jejak tumpukan penuh untuk semua utas dengan menekan Ctrl+Breakdi Windows atau dengan mengirim kill pid --QUITdi Linux.


Saya ingin mengakses daftar dalam kelas java saya
Kryten

Dalam hal ini lihat jawaban cletus.
pjp

3
Um, mengapa orang-orang memilih ini ketika orang itu mengatakan dia menginginkan solusi terprogram?
cletus

Karena pertanyaannya tidak menyatakan itu. Saya akan mengedit pertanyaan untuk membuatnya eksplisit.
pjp

8

Pengguna Apache Commons dapat digunakan ThreadUtils. Implementasi saat ini menggunakan pendekatan walk the thread group yang telah diuraikan sebelumnya.

for (Thread t : ThreadUtils.getAllThreads()) {
      System.out.println(t.getName() + ", " + t.isDaemon());
}

7

Anda dapat mencoba sesuatu seperti ini:

Thread.getAllStackTraces().keySet().forEach((t) -> System.out.println(t.getName() + "\nIs Daemon " + t.isDaemon() + "\nIs Alive " + t.isAlive()));

dan Anda jelas bisa mendapatkan lebih banyak karakteristik utas jika Anda membutuhkan.


5

Di Groovy Anda dapat memanggil metode pribadi

// Get a snapshot of the list of all threads 
Thread[] threads = Thread.getThreads()

Di Jawa , Anda bisa memanggil metode itu menggunakan refleksi asalkan manajer keamanan mengizinkannya.


Saya mendapatkan kesalahan, getThreads tidak ditentukan untuk Thread. Dan saya tidak melihat fungsi ini dalam dokumentasi.

4

Cuplikan kode untuk mendapatkan daftar utas dimulai oleh utas utama:

import java.util.Set;

public class ThreadSet {
    public static void main(String args[]) throws Exception{
        Thread.currentThread().setName("ThreadSet");
        for ( int i=0; i< 3; i++){
            Thread t = new Thread(new MyThread());
            t.setName("MyThread:"+i);
            t.start();
        }
        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
        for ( Thread t : threadSet){
            if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup()){
                System.out.println("Thread :"+t+":"+"state:"+t.getState());
            }
        }
    }
}

class MyThread implements Runnable{
    public void run(){
        try{
            Thread.sleep(5000);
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

keluaran:

Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE

Jika Anda memerlukan semua utas termasuk utas sistem, yang belum dimulai oleh program Anda, hapus kondisi di bawah ini.

if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup())

Sekarang output:

Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[Reference Handler,10,system]:state:WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[Finalizer,8,system]:state:WAITING
Thread :Thread[Signal Dispatcher,9,system]:state:RUNNABLE
Thread :Thread[Attach Listener,5,system]:state:RUNNABLE

3
    public static void main(String[] args) {


        // Walk up all the way to the root thread group
        ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
        ThreadGroup parent;
        while ((parent = rootGroup.getParent()) != null) {
            rootGroup = parent;
        }

        listThreads(rootGroup, "");
    }


    // List all threads and recursively list all subgroup
    public static void listThreads(ThreadGroup group, String indent) {
        System.out.println(indent + "Group[" + group.getName() + 
                ":" + group.getClass()+"]");
        int nt = group.activeCount();
        Thread[] threads = new Thread[nt*2 + 10]; //nt is not accurate
        nt = group.enumerate(threads, false);

        // List every thread in the group
        for (int i=0; i<nt; i++) {
            Thread t = threads[i];
            System.out.println(indent + "  Thread[" + t.getName() 
                    + ":" + t.getClass() + "]");
        }

        // Recursively list all subgroups
        int ng = group.activeGroupCount();
        ThreadGroup[] groups = new ThreadGroup[ng*2 + 10];
        ng = group.enumerate(groups, false);

        for (int i=0; i<ng; i++) {
            listThreads(groups[i], indent + "  ");
        }
    }

3

Di konsol java, tekan Ctrl-Break . Ini akan mencantumkan semua utas ditambah beberapa informasi tentang heap. Ini tidak akan memberi Anda akses ke objek tentu saja. Tapi itu bisa sangat membantu untuk debugging.


1

Untuk mendapatkan daftar utas dan status lengkapnya menggunakan terminal, Anda dapat menggunakan perintah di bawah ini:

jstack -l <PID>

PID mana yang merupakan id proses yang berjalan di komputer Anda. Untuk mendapatkan id proses dari proses java Anda, Anda cukup menjalankan jpsperintah.

Selain itu, Anda dapat menganalisis dump thread Anda yang dihasilkan oleh jstack di TDA (Thread Dump Analyzer) seperti alat penganalisa benang fastthread atau spotify .


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.