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.

Kryten
sumber

Jawaban:

325

Untuk mendapatkan perangkat yang dapat diubah:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
thejoshwolfe
sumber
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.

Frerich Raabe
sumber
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.

cletus
sumber
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.

pjp
sumber
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());
}
gerardw
sumber
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.

hasskell
sumber
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.

Jarek Przygódzki
sumber
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
Ravindra babu
sumber
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 + "  ");
        }
    }
ZZ Coder
sumber
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.

raoulsson
sumber
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 .

Amir Fo
sumber