Lấy danh sách tất cả các luồng hiện đang chạy trong Java


232

Có cách nào tôi có thể nhận được một danh sách tất cả các luồng đang chạy trong JVM hiện tại không (bao gồm cả các luồng không được bắt đầu bởi lớp của tôi) không?

Có phải cũng có thể có được ThreadClass các đối tượng của tất cả các chủ đề trong danh sách?

Tôi muốn có thể làm điều này thông qua mã.

Câu trả lời:


325

Để có được một bộ lặp:

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

19
Mặc dù sạch hơn nhiều so với đề xuất thay thế khác, điều này có nhược điểm là phát sinh chi phí để có được dấu vết ngăn xếp cho tất cả các luồng. Nếu bạn sẽ sử dụng những dấu vết ngăn xếp này, điều này rõ ràng là vượt trội. Nếu không, thì điều này có thể chậm hơn đáng kể vì không có lợi ích nào ngoài mã sạch.
Eddie

29
@Eddie Đó có phải là một giả định từ lẽ thường, hay bạn đã làm thí nghiệm? "chậm hơn đáng kể" bạn nói; chậm hơn bao nhiêu Nó có đáng không? Tôi nghi ngờ bất kỳ nỗ lực nào để làm cho mã tồi tệ hơn vì mục đích hiệu quả. Nếu bạn có một yêu cầu về hiệu quả cơ sở hạ tầng để đo lường hiệu quả một cách định lượng, thì tôi sẽ ổn với những người làm cho mã kém hơn, bởi vì họ dường như biết họ đang làm gì. Xem căn nguyên của mọi tội lỗi theo Donald Knuth.
thejoshwolfe

20
Tôi đã không tính thời gian cho các lựa chọn thay thế cụ thể này, nhưng tôi đã làm việc với các phương tiện Java khác để thu thập dấu vết ngăn xếp so với chỉ một danh sách các luồng. Tác động hiệu năng dường như phụ thuộc rất nhiều vào JVM mà bạn đang sử dụng (ví dụ: JRockit vs Sun JVM). Đó là giá trị đo lường trong trường hợp cụ thể của bạn. Nó có ảnh hưởng đến bạn hay không tùy thuộc vào lựa chọn JVM của bạn và vào số lượng luồng bạn có. Tôi thấy rằng nhận được tất cả các dấu vết ngăn xếp thông qua ThreadMXBean.dumpAllThreads cho khoảng 250 luồng để lấy 150 - 200 msec trong khi chỉ nhận được danh sách các luồng (không có dấu vết) để không thể đo lường được (0 msec).
Eddie

4
Trên hệ thống của tôi (Oracle Java 1.7 VM), kiểm tra nhanh cho thấy phương pháp này ~ 70..80 lần SLOWER so với phương pháp thay thế bên dưới. Dấu vết ngăn xếp và sự phản chiếu thuộc về các hoạt động Java nặng nhất.
Franz D.

5
@thejoshwolfe: Tất nhiên, khả năng đọc là một yếu tố quan trọng và người ta không nên tối ưu hóa vi mô, v.v. Tuy nhiên, tôi đã nghiên cứu trong khi viết một màn hình hiệu suất ứng dụng nhỏ. Đối với loại công cụ này, một dấu ấn hiệu suất tối thiểu là điều cần thiết để có được dữ liệu đáng tin cậy, vì vậy tôi đã chọn phương pháp stacktrace-less.
Franz D.

75

Nhận một xử lý đến thư mục gốc ThreadGroup, như thế này:

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

Bây giờ, gọi enumerate()hàm trên nhóm gốc nhiều lần. Đối số thứ hai cho phép bạn nhận được tất cả các chủ đề, đệ quy:

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

Lưu ý cách chúng ta gọi enum Cả () liên tục cho đến khi mảng đủ lớn để chứa tất cả các mục.


22
Tôi bị sốc vì chiến lược này rất phổ biến trên internet. Chiến lược của tôi đơn giản hơn (1 dòng mã) và hoạt động tốt với phần thưởng thêm vào để tránh các điều kiện cuộc đua.
thejoshwolfe

11
@thejoshwolfe: Thật ra, tôi đồng ý - Tôi nghĩ câu trả lời của bạn tốt hơn nhiều, và có lẽ nó sẽ là câu trả lời được chấp nhận ngay từ đầu nếu nó không bị trễ một năm. Nếu OP vẫn thường xuyên gặp SO, điều mà anh ta dường như làm, anh ta sẽ được khuyên không nên chấp nhận câu trả lời của tôi và chấp nhận câu trả lời của bạn.
Frerich Raabe

2
Lưu ý rằng đối với bất cứ điều gì khác rootGroup, bạn nên sử dụng new Thread[rootGroup.activeCount()+1]. activeCount()có thể bằng không, và nếu là bạn sẽ chạy vào một vòng lặp vô hạn.
jmiserez

7
@thejoshwolfe Tôi cho rằng giải pháp này ít tốn kém hơn nhiều.
Haozhun

19
+1 cho câu trả lời bị đánh giá thấp này, vì nó phù hợp hơn nhiều cho mục đích giám sát IMHO. Điều kiện chủng tộc vốn có của nó không quan trọng lắm trong việc giám sát. Tuy nhiên, như một số thử nghiệm nhanh chóng cho thấy, nó nhanh hơn khoảng 70-80 lần so với giải pháp dựa trên stacktrace. Để theo dõi, một dấu ấn hiệu suất nhỏ là rất cần thiết, vì bạn sẽ muốn giữ các hiệu ứng trên hệ thống được giám sát càng nhỏ càng tốt (Heisenberg đình công một lần nữa :) Để gỡ lỗi, trong đó bạn có thể cần thông tin đáng tin cậy hơn, phương pháp stacktrace có thể Thiết yếu. BTW, giải pháp MxBean thậm chí còn chậm hơn so với sử dụng stacktraces.
Franz D.

29

Vâng, hãy xem để có được một danh sách các chủ đề . Rất nhiều ví dụ trên trang đó.

Đó là để làm điều đó lập trình. Nếu bạn chỉ muốn một danh sách trên Linux thì ít nhất bạn có thể sử dụng lệnh này:

kill -3 processid

và VM sẽ thực hiện kết xuất luồng vào thiết bị xuất chuẩn.


5
giết -3? Ít nhất là trên linux của tôi, đó là "thiết bị đầu cuối thoát". Giết chóc, không liệt kê.
Michael H.

5
cletus thực sự chính xác - một kill -3 sẽ kết xuất luồng vào thiết bị xuất chuẩn, bất kể tín hiệu đó có nghĩa là gì. Tôi sẽ xem xét sử dụng jstack thay thế.
Dan Hardiker

không thể truy cập danh sách các chủ đề : nadeausoftware.com từ chối kết nối.
DSlomer64


14

Bạn đã xem jconsole ?

Điều này sẽ liệt kê tất cả các luồng đang chạy cho một quy trình Java cụ thể.

Bạn có thể bắt đầu jconsole từ thư mục bin JDK.

Bạn cũng có thể nhận được một dấu vết ngăn xếp đầy đủ cho tất cả các luồng bằng cách nhấn Ctrl+Breaktrong Windows hoặc bằng cách gửi kill pid --QUITtrong Linux.


Tôi muốn truy cập danh sách trong lớp java của mình
Kryten

Trong trường hợp đó, hãy nhìn vào câu trả lời của cletus.
pjp

3
Ừm, tại sao mọi người bỏ phiếu này khi anh chàng nói rằng anh ta muốn một giải pháp lập trình?
cletus

Bởi vì câu hỏi không nói lên điều đó. Tôi sẽ chỉnh sửa câu hỏi để làm cho nó rõ ràng.
pjp

8

Người dùng Apache Commons có thể sử dụng ThreadUtils. Việc thực hiện hiện tại sử dụng cách tiếp cận nhóm chủ đề được phác thảo trước đó.

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

7

Bạn có thể thử một cái gì đó như thế này:

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

và rõ ràng bạn có thể nhận được nhiều đặc điểm chủ đề hơn nếu bạn cần.


5

Trong Groovy, bạn có thể gọi các phương thức riêng tư

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

Trong Java , bạn có thể gọi phương thức đó bằng cách sử dụng sự phản chiếu miễn là trình quản lý bảo mật cho phép nó.


Tôi gặp lỗi, getThreads không được xác định cho Chủ đề. Và tôi không thấy chức năng này trong tài liệu.

4

Đoạn mã để có danh sách các chủ đề được bắt đầu bởi chủ đề chính:

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

đầu ra:

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

Nếu bạn cần tất cả các luồng bao gồm các luồng hệ thống, chương trình chưa được khởi động bởi chương trình của bạn, hãy xóa điều kiện bên dưới.

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

Bây giờ đầu ra:

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

Trong bảng điều khiển java, nhấn Ctrl-Break . Nó sẽ liệt kê tất cả các chủ đề cộng với một số thông tin về heap. Điều này sẽ không cung cấp cho bạn quyền truy cập vào các đối tượng của khóa học. Nhưng dù sao nó cũng có thể rất hữu ích cho việc gỡ lỗi.


1

Để có được danh sách các luồng và trạng thái đầy đủ của chúng bằng thiết bị đầu cuối, bạn có thể sử dụng lệnh dưới đây:

jstack -l <PID>

Mà PID là id của tiến trình đang chạy trên máy tính của bạn. Để có được id quá trình của quá trình java của bạn, bạn chỉ cần chạy jpslệnh.

Ngoài ra, bạn có thể phân tích bãi chứa thread của bạn mà sản xuất bởi jstack trong TDAs (Chủ đề Dump Analyzer) như fastthread hoặc công cụ chủ đề phân tích Spotify .


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.