Lớp ThreadGroup
(Class ThreadGroup)

Java cung cấp một cách tiện lợi để nhóm nhiều luồng trong một đối tượng. Bằng cách này, chúng ta có thể tạm dừng, tiếp tục hoặc ngắt một nhóm luồng bằng cách gọi một phương thức duy nhất.

Lưu ý: Hiện tại, các phương thức suspend(), resume(), và stop() đã bị gỡ bỏ.

Nhóm luồng trong Java được triển khai bởi lớp java.lang.ThreadGroup.

Lớp ThreadGroup đại diện cho một tập hợp các luồng. Ngoài ra, một nhóm luồng cũng có thể bao gồm các nhóm luồng khác. Các nhóm luồng tạo thành một cấu trúc cây, trong đó mọi nhóm luồng, ngoại trừ nhóm luồng gốc (initial thread group), đều có một nhóm cha.

Các điểm quan trọng trong lớp ThreadGroup:

↳ Cấu trúc cây: Các nhóm luồng tạo ra một cấu trúc cây, giúp tổ chức và quản lý các luồng theo nhóm. Nhóm luồng gốc là điểm bắt đầu của cấu trúc này và không có nhóm cha.

↳ Quyền truy cập: Một luồng có thể truy cập thông tin về nhóm luồng của chính nó, nhưng không thể truy cập thông tin về nhóm cha của nhóm luồng đó hoặc bất kỳ nhóm luồng nào khác.

↳ Giao diện UncaughtExceptionHandler: Lớp ThreadGroup triển khai giao diện Thread.UncaughtExceptionHandler, cho phép xử lý các ngoại lệ không được xử lý trong các luồng thuộc nhóm.

Khai báo lớp ThreadGroup trong Java

Khi sử dụng lớp ThreadGroup trong Java, bạn không cần phải thực hiện thao tác import đặc biệt. Lớp ThreadGroup nằm trong gói java.lang, và gói này được import tự động vào mọi chương trình Java.

Cú pháp khai báo lớp ThreadGroup:

Cú pháp

public class ThreadGroup
extends Object
implements Thread.UncaughtExceptionHandler

Dưới đây là giải thích chi tiết về cú pháp khai báo này:

↳ public class ThreadGroup: Đây là khai báo một lớp công khai (public) tên là ThreadGroup. Lớp này có thể được truy cập từ bất kỳ đâu trong dự án Java, miễn là nó được import hoặc ở cùng gói.

↳ Kế thừa từ Object: ThreadGroup kế thừa từ lớp cơ sở Object, do đó nó có các phương thức cơ bản của lớp Object, chẳng hạn như toString(), equals(), và hashCode().

↳ implements Thread.UncaughtExceptionHandler: ThreadGroup triển khai giao diện Thread.UncaughtExceptionHandler. Giao diện này cho phép ThreadGroup xử lý các ngoại lệ chưa được bắt (uncaught exceptions) được ném ra từ các luồng thuộc nhóm.

Các constructor của lớp ThreadGroup

Lớp ThreadGroup cung cấp hai hàm khởi tạo để tạo nhóm luồng:

↳ ThreadGroup(String name): Tạo ra một nhóm luồng mới với tên được chỉ định. Nhóm luồng này sẽ là con của nhóm luồng hiện tại đang chạy.

↳ ThreadGroup(ThreadGroup parent, String name): Tạo ra một nhóm luồng mới với tên được chỉ định và nhóm luồng cha được chỉ định. Điều này cho phép bạn tạo một cấu trúc phân cấp của các nhóm luồng.

Các phương thức của lớp ThreadGroup

Lớp ThreadGroup trong Java đại diện cho một nhóm các luồng. Các phương thức của lớp này chủ yếu được sử dụng để quản lý và truy cập thông tin về các luồng trong nhóm. Dưới đây là danh sách tất cả các phương thức của lớp ThreadGroup trong Java:

↳ activeCount(): Trả về số lượng luồng đang hoạt động trong nhóm luồng hiện tại và các nhóm con của nó.

↳ activeGroupCount(): Trả về số lượng nhóm luồng đang hoạt động trong nhóm luồng hiện tại và các nhóm con của nó.

↳ checkAccess(): Kiểm tra xem luồng hiện tại có quyền sửa đổi nhóm luồng này hay không.

↳ destroy(): Phá hủy nhóm luồng hiện tại và tất cả các nhóm con của nó.

↳ isDestroyed(): Kiểm tra xem nhóm luồng đã bị phá hủy hay chưa.

↳ enumerate(Thread[] list): Sao chép các luồng đang hoạt động trong nhóm luồng hiện tại và các nhóm con của nó vào mảng list đã cho.

↳ enumerate(Thread[] list, boolean recurse): Sao chép các luồng đang hoạt động trong nhóm luồng hiện tại (nếu recurse là false) hoặc trong nhóm luồng hiện tại và các nhóm con của nó (nếu recurse là true) vào mảng list đã cho.

↳ enumerate(ThreadGroup[] list): Sao chép các nhóm luồng con đang hoạt động trong nhóm luồng hiện tại và các nhóm con của nó vào mảng list đã cho.

↳ enumerate(ThreadGroup[] list, boolean recurse): Sao chép các nhóm luồng con đang hoạt động trong nhóm luồng hiện tại (nếu recurse là false) hoặc trong nhóm luồng hiện tại và các nhóm con của nó (nếu recurse là true) vào mảng list đã cho.

↳ getMaxPriority(): Trả về mức ưu tiên tối đa của các luồng trong nhóm luồng này.

↳ setMaxPriority(int pri): Thiết lập mức ưu tiên tối đa cho các luồng trong nhóm.

↳ getName(): Trả về tên của nhóm luồng.

↳ getParent(): Trả về nhóm luồng cha của nhóm luồng hiện tại.

↳ parentOf(ThreadGroup g): Kiểm tra xem nhóm luồng hiện tại là cha của nhóm luồng hay không.

↳ interrupt(): Ngắt tất cả các luồng trong nhóm luồng này.

↳ isDaemon(): Kiểm tra xem nhóm luồng là daemon hay không.

↳ setDaemon(boolean daemon): Đặt trạng thái daemon cho nhóm luồng.

↳ list(): In thông tin về nhóm luồng ra màn hình console.

↳ uncaughtException(Thread t, Throwable e): Được gọi khi một luồng trong nhóm bị kết thúc đột ngột do ngoại lệ không được bắt.

Các phương thức đã lỗi thời

↳ allowThreadSuspension(boolean b), resume(), suspend(), stop(): Các phương thức này đã bị lỗi thời và không nên sử dụng vì tiềm ẩn các vấn đề như deadlock.

Dưới đây là một ví dụ chi tiết về cách sử dụng lớp ThreadGroup trong Java để tạo và quản lý các luồng (threads). Ví dụ này sẽ tạo một nhóm luồng, thêm một số luồng vào nhóm, và sau đó liệt kê thông tin về nhóm và các luồng trong nhóm.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        System.out.println("Nhóm luồng: " + Thread.currentThread().getThreadGroup().getName());
        try {
            // Giả lập công việc
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("Luồng bị gián đoạn.");
        }
    }
}

public class Example {
    public static void main(String[] args) {
        // Tạo một nhóm luồng mới với tên "MyThreadGroup"
        ThreadGroup group = new ThreadGroup("MyThreadGroup");

        // Tạo và khởi động các luồng trong nhóm
        Thread t1 = new Thread(group, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(group, new MyRunnable(), "Thread-2");
        Thread t3 = new Thread(group, new MyRunnable(), "Thread-3");

        t1.start();
        t2.start();
        t3.start();

        // Liệt kê thông tin về nhóm luồng và các luồng trong nhóm
        System.out.println("Thông tin về nhóm luồng:");
        group.list();

        // Đợi một chút để các luồng thực thi
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Thông tin về nhóm luồng:
Tên luồng: Thread-2
Nhóm luồng: MyThreadGroup
Tên luồng: Thread-3
Nhóm luồng: MyThreadGroup
Tên luồng: Thread-1
Nhóm luồng: MyThreadGroup
java.lang.ThreadGroup[name=MyThreadGroup,maxpri=10]
Thread[#20,Thread-1,5,MyThreadGroup]
Thread[#21,Thread-2,5,MyThreadGroup]
Thread[#22,Thread-3,5,MyThreadGroup]
Kết thúc chương trình

Giải thích đầu ra:

↳ Mỗi luồng in tên của nó và tên nhóm luồng mà nó thuộc về.

↳ group.list(); liệt kê tất cả các luồng trong nhóm và cung cấp thông tin chi tiết về nhóm luồng.

Ví dụ: Sử dụng phương thức activeCount()

Trong ví dụ này, chúng ta sẽ tạo một nhóm luồng, khởi động một số luồng trong nhóm, và sau đó sử dụng phương thức activeCount() để đếm số lượng luồng đang hoạt động trong nhóm.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // In ra tên luồng
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        try {
            // Giả lập công việc
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("Luồng bị gián đoạn.");
        }
    }
}

public class Example {
    public static void main(String[] args) {
        // Tạo một nhóm luồng mới với tên "MyThreadGroup"
        ThreadGroup group = new ThreadGroup("MyThreadGroup");

        // Tạo và khởi động các luồng trong nhóm
        Thread t1 = new Thread(group, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(group, new MyRunnable(), "Thread-2");
        Thread t3 = new Thread(group, new MyRunnable(), "Thread-3");

        // Khởi động các luồng
        t1.start();
        t2.start();
        t3.start();

        // Đếm số lượng luồng đang hoạt động trong nhóm
        int activeCount = group.activeCount();
        System.out.println("Số lượng luồng đang hoạt động trong nhóm: " + activeCount);

        // Đợi một chút để các luồng hoàn tất
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Kiểm tra lại số lượng luồng đang hoạt động sau khi các luồng đã hoàn tất
        activeCount = group.activeCount();
        System.out.println("Số lượng luồng đang hoạt động trong nhóm sau khi các luồng hoàn tất: " + activeCount);

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Tên luồng: Thread-3
Tên luồng: Thread-2
Tên luồng: Thread-1
Số lượng luồng đang hoạt động trong nhóm: 3
Số lượng luồng đang hoạt động trong nhóm sau khi các luồng hoàn tất: 0
Kết thúc chương trình.

Phương thức activeCount() cung cấp cách để đếm số lượng luồng đang hoạt động trong một nhóm luồng tại một thời điểm cụ thể. Đây là một công cụ hữu ích để theo dõi trạng thái của các luồng trong ứng dụng của bạn.

Ví dụ: Sử dụng phương thức enumerate()

Trong ví dụ này, chúng ta sẽ tạo một nhóm luồng, thêm một số luồng vào nhóm, và sau đó sử dụng phương thức enumerate() để lấy tất cả các luồng trong nhóm và in thông tin về chúng.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // In ra tên luồng
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        try {
            // Giả lập công việc
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("Luồng bị gián đoạn.");
        }
    }
}

public class Example {
    public static void main(String[] args) {
        // Tạo một nhóm luồng mới với tên "MyThreadGroup"
        ThreadGroup group = new ThreadGroup("MyThreadGroup");

        // Tạo và khởi động các luồng trong nhóm
        Thread t1 = new Thread(group, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(group, new MyRunnable(), "Thread-2");
        Thread t3 = new Thread(group, new MyRunnable(), "Thread-3");

        // Khởi động các luồng
        t1.start();
        t2.start();
        t3.start();

        // Đợi một chút để các luồng thực thi
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Liệt kê tất cả các luồng trong nhóm
        Thread[] threads = new Thread[group.activeCount()];
        group.enumerate(threads);

        System.out.println("Danh sách các luồng trong nhóm:");
        for (Thread thread : threads) {
            if (thread != null) {
                System.out.println("Tên luồng: " + thread.getName());
            }
        }

        // Đợi các luồng hoàn tất
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Tên luồng: Thread-1
Tên luồng: Thread-2
Tên luồng: Thread-3
Danh sách các luồng trong nhóm:
Tên luồng: Thread-1
Tên luồng: Thread-2
Tên luồng: Thread-3
Kết thúc chương trình.

Phương thức enumerate(Thread[] threads) là một công cụ hữu ích để lấy danh sách các luồng trong một nhóm và thực hiện các hoạt động tiếp theo với danh sách đó, chẳng hạn như in ra thông tin hoặc phân tích trạng thái của các luồng.

Ví dụ: Sử dụng phương thức getMaxPriority() và setMaxPriority(int pri)

Trong ví dụ này, chúng ta sẽ:

↳ Tạo một nhóm luồng với mức ưu tiên tối đa.

↳ Thiết lập mức ưu tiên tối đa cho nhóm.

↳ Tạo và khởi động một số luồng trong nhóm.

↳ Sử dụng getMaxPriority() để lấy mức ưu tiên tối đa của nhóm.

↳ Thay đổi mức ưu tiên tối đa của nhóm và kiểm tra lại.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // In ra tên luồng và mức ưu tiên của nó
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        System.out.println("Mức ưu tiên của luồng: " + Thread.currentThread().getPriority());
    }
}

public class Example{
    public static void main(String[] args) {
        // Tạo nhóm luồng với tên "MyThreadGroup"
        ThreadGroup group = new ThreadGroup("MyThreadGroup");
        
        // Thiết lập mức ưu tiên tối đa cho nhóm luồng
        group.setMaxPriority(7);
        
        // Tạo các luồng và thiết lập mức ưu tiên cho chúng
        Thread t1 = new Thread(group, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(group, new MyRunnable(), "Thread-2");
        Thread t3 = new Thread(group, new MyRunnable(), "Thread-3");

        t1.setPriority(4); // Mức ưu tiên thấp hơn mức tối đa của nhóm
        t2.setPriority(8); // Mức ưu tiên cao hơn mức tối đa của nhóm
        t3.setPriority(6); // Mức ưu tiên nằm trong khoảng cho phép của nhóm

        // Khởi động các luồng
        t1.start();
        t2.start();
        t3.start();

        // Đợi một chút để các luồng thực thi
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Kiểm tra mức ưu tiên tối đa của nhóm
        int maxPriority = group.getMaxPriority();
        System.out.println("Mức ưu tiên tối đa của nhóm luồng: " + maxPriority);

        // Thay đổi mức ưu tiên tối đa cho nhóm
        group.setMaxPriority(9);
        int newMaxPriority = group.getMaxPriority();
        System.out.println("Mức ưu tiên tối đa mới của nhóm luồng: " + newMaxPriority);

        // Đợi các luồng hoàn tất
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Tên luồng: Thread-1
Tên luồng: Thread-3
Tên luồng: Thread-2
Mức ưu tiên của luồng: 7
Mức ưu tiên của luồng: 6
Mức ưu tiên của luồng: 4
Mức ưu tiên tối đa của nhóm luồng: 7
Mức ưu tiên tối đa mới của nhóm luồng: 9
Kết thúc chương trình.

Các phương thức getMaxPriority() và setMaxPriority(int pri) của lớp ThreadGroup giúp bạn quản lý mức ưu tiên của các luồng trong nhóm. Phương thức getMaxPriority() cho phép bạn kiểm tra mức ưu tiên tối đa hiện tại, trong khi setMaxPriority(int pri) cho phép bạn thay đổi mức ưu tiên tối đa cho nhóm luồng.

Ví dụ: Sử dụng phương thức destroy() và isDestroyed()

Trong ví dụ này, chúng ta sẽ:

↳ Tạo một nhóm luồng chính và nhóm con.

↳ Tạo một số luồng trong nhóm và nhóm con.

↳ Sử dụng phương thức destroy() để phá hủy nhóm và tất cả các nhóm con của nó.

↳ Kiểm tra trạng thái của nhóm luồng bằng phương thức isDestroyed().

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // In ra tên luồng và chờ một chút
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("Luồng bị gián đoạn.");
        }
    }
}

public class Example{
    public static void main(String[] args) {
        // Tạo nhóm luồng chính với tên "MainGroup"
        ThreadGroup mainGroup = new ThreadGroup("MainGroup");
        
        // Tạo nhóm con với tên "SubGroup"
        ThreadGroup subGroup = new ThreadGroup(mainGroup, "SubGroup");

        // Tạo luồng trong nhóm chính
        Thread t1 = new Thread(mainGroup, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(mainGroup, new MyRunnable(), "Thread-2");

        // Tạo luồng trong nhóm con
        Thread t3 = new Thread(subGroup, new MyRunnable(), "Thread-3");
        Thread t4 = new Thread(subGroup, new MyRunnable(), "Thread-4");

        // Khởi động các luồng
        t1.start();
        t2.start();
        t3.start();
        t4.start();

        // Đợi một chút để các luồng thực thi
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Kiểm tra trạng thái của nhóm luồng
        System.out.println("Nhóm chính đã bị phá hủy: " + mainGroup.isDestroyed());
        System.out.println("Nhóm con đã bị phá hủy: " + subGroup.isDestroyed());

        // Phá hủy nhóm chính (bao gồm cả nhóm con)
        mainGroup.destroy();

        // Kiểm tra lại trạng thái của nhóm luồng sau khi phá hủy
        System.out.println("Nhóm chính đã bị phá hủy sau khi gọi destroy(): " + mainGroup.isDestroyed());
        System.out.println("Nhóm con đã bị phá hủy sau khi gọi destroy(): " + subGroup.isDestroyed());

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Tên luồng: Thread-3
Tên luồng: Thread-2
Tên luồng: Thread-1
Tên luồng: Thread-4
Nhóm chính đã bị phá hủy: false
Nhóm con đã bị phá hủy: false
Nhóm chính đã bị phá hủy sau khi gọi destroy(): false
Nhóm con đã bị phá hủy sau khi gọi destroy(): false
Kết thúc chương trình.

Các phương thức destroy() và isDestroyed() cho phép bạn quản lý và kiểm tra trạng thái của nhóm luồng trong Java. Phương thức destroy() sẽ phá hủy nhóm luồng và tất cả các nhóm con của nó, trong khi isDestroyed() cho phép bạn kiểm tra xem nhóm luồng đã bị phá hủy hay chưa.

Ví dụ: Sử sụng phương thức isDaemon() và setDaemon(boolean daemon)

Trong ví dụ này, chúng ta sẽ:

↳ Tạo một nhóm luồng.

↳ Đặt trạng thái daemon cho nhóm luồng.

↳ Kiểm tra trạng thái daemon của nhóm luồng.

↳ Thay đổi trạng thái daemon và kiểm tra lại.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // In ra tên luồng và trạng thái daemon của nhóm luồng
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        System.out.println("Trạng thái daemon của nhóm luồng: " + Thread.currentThread().getThreadGroup().isDaemon());
        try {
            // Giả lập công việc
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("Luồng bị gián đoạn.");
        }
    }
}

public class Example {
    public static void main(String[] args) {
        // Tạo nhóm luồng mới với tên "MyThreadGroup"
        ThreadGroup group = new ThreadGroup("MyThreadGroup");

        // Kiểm tra trạng thái daemon trước khi thiết lập
        System.out.println("Nhóm luồng có phải là daemon trước khi thiết lập: " + group.isDaemon());

        // Thiết lập nhóm luồng thành daemon
        group.setDaemon(true);

        // Kiểm tra trạng thái daemon sau khi thiết lập
        System.out.println("Nhóm luồng có phải là daemon sau khi thiết lập: " + group.isDaemon());

        // Tạo và khởi động các luồng trong nhóm
        Thread t1 = new Thread(group, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(group, new MyRunnable(), "Thread-2");

        t1.start();
        t2.start();

        // Đợi một chút để các luồng thực thi
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Đợi các luồng hoàn tất
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Nhóm luồng có phải là daemon trước khi thiết lập: false
Nhóm luồng có phải là daemon sau khi thiết lập: true
Tên luồng: Thread-1
Tên luồng: Thread-2
Trạng thái daemon của nhóm luồng: true
Trạng thái daemon của nhóm luồng: true
Kết thúc chương trình.

Các phương thức isDaemon() và setDaemon(boolean daemon) cho phép bạn kiểm tra và thiết lập trạng thái daemon cho nhóm luồng trong Java. Phương thức isDaemon() giúp bạn xác định xem nhóm luồng có phải là daemon hay không, trong khi setDaemon(boolean daemon) cho phép bạn thay đổi trạng thái daemon của nhóm luồng.

Ví dụ: Sử dụng phương thức getParent() và parentOf(ThreadGroup g)

Trong ví dụ này, chúng ta sẽ:

↳ Tạo một nhóm luồng chính và một nhóm con.

↳ Sử dụng phương thức getParent() để lấy nhóm cha của nhóm con.

↳ Sử dụng phương thức parentOf(ThreadGroup g) để kiểm tra xem nhóm cha có phải là cha của nhóm con không.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // In ra tên luồng và chờ một chút
        System.out.println("Tên luồng: " + Thread.currentThread().getName());
        try {
            // Giả lập công việc
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("Luồng bị gián đoạn.");
        }
    }
}

public class Example {
    public static void main(String[] args) {
        // Tạo nhóm luồng chính với tên "MainGroup"
        ThreadGroup mainGroup = new ThreadGroup("MainGroup");
        
        // Tạo nhóm con với tên "SubGroup"
        ThreadGroup subGroup = new ThreadGroup(mainGroup, "SubGroup");

        // Kiểm tra nhóm cha của nhóm con
        ThreadGroup parentGroup = subGroup.getParent();
        System.out.println("Tên nhóm cha của nhóm con: " + parentGroup.getName());

        // Kiểm tra xem nhóm chính có phải là cha của nhóm con không
        boolean isParent = mainGroup.parentOf(subGroup);
        System.out.println("Nhóm chính có phải là cha của nhóm con không: " + isParent);

        // Khởi động các luồng trong nhóm
        Thread t1 = new Thread(mainGroup, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(subGroup, new MyRunnable(), "Thread-2");

        t1.start();
        t2.start();

        // Đợi một chút để các luồng thực thi
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Đợi các luồng hoàn tất
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Tên nhóm cha của nhóm con: MainGroup
Nhóm chính có phải là cha của nhóm con không: true
Tên luồng: Thread-2
Tên luồng: Thread-1
Kết thúc chương trình.

Các phương thức getParent() và parentOf(ThreadGroup g) giúp bạn quản lý và kiểm tra quan hệ giữa các nhóm luồng trong Java. Phương thức getParent() trả về nhóm cha của nhóm luồng hiện tại, trong khi parentOf(ThreadGroup g) kiểm tra xem nhóm luồng hiện tại có phải là cha của một nhóm luồng khác hay không.

Ví dụ: Sử dụng phương thức interrupt()

Trong ví dụ này, chúng ta sẽ:

↳ Tạo một nhóm luồng và một số luồng trong nhóm đó.

↳ Sử dụng phương thức interrupt() để ngắt tất cả các luồng trong nhóm.

Ví dụ: Example.java

class MyRunnable implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                // Giả lập công việc bằng cách ngủ
                System.out.println("Luồng " + Thread.currentThread().getName() + " đang chạy.");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // Xử lý gián đoạn
                System.out.println("Luồng " + Thread.currentThread().getName() + " đã bị gián đoạn.");
                Thread.currentThread().interrupt(); // Đặt lại trạng thái gián đoạn
            }
        }
        System.out.println("Luồng " + Thread.currentThread().getName() + " đã dừng.");
    }
}

public class Example {
    public static void main(String[] args) {
        // Tạo nhóm luồng chính với tên "MyThreadGroup"
        ThreadGroup group = new ThreadGroup("MyThreadGroup");

        // Tạo và khởi động các luồng trong nhóm
        Thread t1 = new Thread(group, new MyRunnable(), "Thread-1");
        Thread t2 = new Thread(group, new MyRunnable(), "Thread-2");

        t1.start();
        t2.start();

        // Đợi một chút để các luồng bắt đầu chạy
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Ngắt tất cả các luồng trong nhóm
        System.out.println("Ngắt tất cả các luồng trong nhóm.");
        group.interrupt();

        // Đợi các luồng hoàn tất
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Kết thúc chương trình.");
    }
}

Kết quả của chương trình là

Luồng Thread-2 đang chạy.
Luồng Thread-1 đang chạy.
Luồng Thread-1 đang chạy.
Luồng Thread-2 đang chạy.
Luồng Thread-2 đang chạy.
Luồng Thread-1 đang chạy.
Ngắt tất cả các luồng trong nhóm.
Luồng Thread-1 đã bị gián đoạn.
Luồng Thread-1 đã dừng.
Luồng Thread-2 đã bị gián đoạn.
Luồng Thread-2 đã dừng.
Kết thúc chương trình.

Phương thức interrupt() của lớp ThreadGroup cho phép bạn gửi tín hiệu gián đoạn đến tất cả các luồng trong nhóm luồng. Điều này giúp bạn quản lý việc dừng các luồng khi cần thiết, chẳng hạn như khi cần kết thúc một nhóm luồng đồng bộ hoặc khi gặp sự cố.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”