Şu anda Java'da çalışmakta olan tüm iş parçacıklarının bir listesini alın


232

Geçerli JVM ( benim sınıf tarafından başlatılmamış konuları da dahil olmak üzere) tüm çalışan iş parçacığı listesini almak için herhangi bir yolu var mı ?

Listedeki tüm evrelerin Threadve Classnesnelerini almak da mümkün müdür ?

Bunu kodla yapabilmek istiyorum.

Yanıtlar:


325

Yinelenebilir bir set almak için:

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

19
Önerilen diğer alternatiften çok daha temiz olmakla birlikte, bu tüm dişler için yığın izleri alma maliyetinin altını çizmektedir. Bu yığın izlerini zaten kullanacaksanız, bu açıkça üstündür. Değilse, bu temiz kod dışında bir kazanç için önemli ölçüde daha yavaş olabilir.
Eddie

29
@Eddie Bu sağduyudan bir varsayım mı yoksa deney yaptınız mı? "önemli ölçüde yavaş" diyorsunuz; ne kadar yavaş? Buna değer mi? Verimlilik uğruna kodu daha da kötüleştirme girişimini sorgularım. Verimliliği nicel olarak ölçmek için bir verimlilik gereksiniminiz ve altyapınız varsa, kodları daha da kötüleştiren insanlar için sorun değil, çünkü ne yaptıklarını biliyorlar. Donald Knuth'a göre tüm kötülüklerin kökenine bakın .
thejoshwolfe

20
Bu belirli alternatifleri zamanlamamıştım, ancak yığın izlerini toplamak için diğer Java araçlarıyla çalıştım. Performans etkisi, hangi JVM'yi kullandığınıza çok güçlü bağlıdır (örneğin JRockit vs Sun JVM). Özel örneğinizde ölçmeye değer. Sizi etkileyip etkilemeyeceği JVM seçiminize ve sahip olduğunuz iplik sayısına bağlıdır. Ben sadece 250 iş parçacığı (izler olmadan) ölçülebilir değil (0 ms) almak için alırken yaklaşık 250 iş parçacığı için yaklaşık 250 iş parçacıkları için ThreadMXBean.dumpAllThreads aracılığıyla tüm yığın izleri alma bulundu.
Eddie

4
Sistemimde (Oracle Java 1.7 VM) hızlı bir kontrol, bu yöntemin aşağıdaki alternatiften ~ 70..80 kez daha zayıf olduğunu gösterir. Yığın izleri ve yansıma, en ağır Java işlemlerine aittir.
Franz

5
@thejoshwolfe: Tabii ki, okunabilirlik önemli bir faktördür ve mikro-optimize etmemelidir vb. Ancak, küçük bir uygulama performans monitörü yazarken araştırmamı yaptım. Bu tür bir araç için, güvenilir veri elde etmek için minimum performans baskısı gereklidir, bu yüzden stacktrace-less yöntemini seçtim.
Franz

75

Kök için bir tanıtıcı alın ThreadGroup, şöyle:

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

Şimdi, enumerate()kök gruptaki işlevi art arda çağırın . İkinci argüman tüm konuları tekrar tekrar elde etmenizi sağlar:

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

Dizi tüm girdileri içerecek kadar büyük olana kadar enumerate () yöntemini nasıl çağırdığımızı unutmayın.


22
Bu stratejinin internette çok popüler olması beni şaşırttı. Stratejim çok daha basit (1 satır kod) ve yarış koşullarından kaçınmanın ek bonusu ile de iyi çalışıyor.
thejoshwolfe

11
@thejoshwolfe: Aslında, katılıyorum - Cevabınızın çok daha iyi olduğunu düşünüyorum ve bir yıl geç kalmazsa muhtemelen ilk etapta kabul edilen cevap olurdu. OP hala görünüşte yaptığı SO'yu sık sık kullanıyorsa, cevabımı kabul etmemesini ve sizin yanıtınızı kabul etmesini tavsiye eder.
Frerich Raabe

2
Bunun dışında herhangi bir şey için rootGroupkullanmanız gerektiğini unutmayın new Thread[rootGroup.activeCount()+1]. activeCount()sıfır olabilir ve eğer öyleyse sonsuz bir döngüye girersiniz.
jmiserez

7
@thejoshwolfe Sanırım bu çözüm çok daha ucuz.
Haozhun

19
IMHO izleme amaçları için çok daha uygun olduğu için bu yetersiz cevap için +1. Doğasında var olan yarış koşulları izleme açısından çok önemli değil. Bununla birlikte, bazı quick'n'dirty testinin gösterdiği gibi, yığın izlemesi tabanlı çözümden yaklaşık 70-80 kat daha hızlıdır. İzleme için, izlenen sistem üzerindeki etkileri olabildiğince küçük tutmak isteyeceğiniz için küçük bir performans baskısı önemlidir (Heisenberg tekrar vurur :) Daha güvenilir bilgilere ihtiyaç duyabileceğiniz hata ayıklama için stacktrace yöntemi esansiyel. BTW, MxBean çözümü yığın izleri kullanmaktan bile daha yavaştır.
Franz

29

Evet, iş parçacığı listesi almaya bakın . Bu sayfada birçok örnek var.

Bunu programlı olarak yapmak. En azından Linux'ta bir liste istiyorsanız, şu komutu kullanabilirsiniz:

kill -3 processid

VM, stdout'a bir iplik dökümü yapacak.


5
-3 öldür? En azından linux'umda, bu "terminalden çık". Öldürür, listelemez.
Michael H.

5
cletus gerçekten doğrudur - bir kill -3, sinyalin ne anlama geldiğine bakılmaksızın stdout'a dökümü yapar. Bunun yerine jstack kullanmayı düşünürdüm.
Dan Hardiker

konuların bir listesini almak ulaşılamıyor: nadeausoftware.com bağlanmayı reddetti.
DSlomer64


14

Jconsole'a bir göz attın mı?

Bu, belirli bir Java işlemi için çalışan tüm evreleri listeler.

Jconsole'u JDK bin klasöründen başlatabilirsiniz.

Ctrl+BreakWindows'da vurarak veya kill pid --QUITLinux'ta göndererek tüm iş parçacıkları için tam yığın izlemesi de alabilirsiniz .


Java sınıfımdaki listeye erişmek istiyorum
Kryten

Bu durumda cletus'un cevabına bakın.
pjp

3
Adam neden programlı bir çözüm istediğini söylediklerinde insanlar bunu oyluyor?
cletus

Çünkü soru bunu söylemiyor. Soruyu açık hale getirmek için düzenleyeceğim.
pjp

8

Apache Commons kullanıcıları kullanabilir ThreadUtils. Mevcut uygulama, daha önce özetlenen iş parçacığı grubu yaklaşımını kullanır.

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

7

Böyle bir şey deneyebilirsiniz:

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

ve ihtiyacınız varsa daha fazla iş parçacığı özelliği elde edebilirsiniz.


5

In Groovy Eğer özel yöntemleri çağırabilir

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

In Java , güvenlik yöneticisi izin vermesi koşuluyla bu yöntem kullanılarak yansıma çağırabilirsiniz.


Hata alıyorum, Konu için getThreads tanımlanmadı. Ve bu işlevi belgelerde görmüyorum.

4

Ana iş parçacığı tarafından başlatılan iş parçacıklarının listesini almak için kod snippet'i:

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

çıktı:

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

Programınız tarafından başlatılmamış sistem konuları da dahil olmak üzere tüm iş parçacıklarına ihtiyacınız varsa, aşağıdaki koşulu kaldırın.

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

Şimdi çıktı:

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

Java konsolunda Ctrl-Break'e basın . Tüm konuları ve yığınla ilgili bazı bilgileri listeler. Bu, elbette nesnelere erişmenizi sağlamaz. Ancak yine de hata ayıklama için çok yararlı olabilir.


1

Terminali kullanarak iş parçacıklarının ve tam durumlarının bir listesini almak için aşağıdaki komutu kullanabilirsiniz:

jstack -l <PID>

Hangi PID, bilgisayarınızda çalışan işlemin kimliğidir. Java işleminizin işlem kimliğini almak için jpskomutu çalıştırabilirsiniz .

Ayrıca, jstack tarafından üretilen iplik dökümünü TDA'larda (Thread Dump Analyzer) hızlı iplik geçirebilir veya spotify iplik analiz aracı olarak analiz edebilirsiniz .


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.